Svarog a4adbabf96
TestBuildBlockErrorCases and remove redundant check of coinbase script length (#1427)
* Write structure of TestBlockBuilderErrorCases

* Remove double verification of script length in serializeCoinbasePayload

* Remove redundant code in TestBuildBlockErrorCases

* Rename povTransactionHash -> povBlockHash

* Convert coinbasePayloadScriptPublicKeyMaxLength to uint8

* Re-use consensus in TestBuildBlockErrorCases
2021-01-19 10:37:51 +02:00

63 lines
3.3 KiB
Go

package coinbasemanager
import (
"encoding/binary"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/pkg/errors"
)
const uint64Len = 8
const uint16Len = 2
const lengthOfscriptPubKeyLength = 1
const lengthOfVersionScriptPubKey = uint16Len
// serializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data.
func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) {
scriptLengthOfScriptPubKey := len(coinbaseData.ScriptPublicKey.Script)
if scriptLengthOfScriptPubKey > int(c.coinbasePayloadScriptPublicKeyMaxLength) {
return nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+
"longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength)
}
payload := make([]byte, uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey+len(coinbaseData.ExtraData))
binary.LittleEndian.PutUint64(payload[:uint64Len], blueScore)
payload[uint64Len] = uint8(coinbaseData.ScriptPublicKey.Version)
payload[uint64Len+lengthOfVersionScriptPubKey] = uint8(len(coinbaseData.ScriptPublicKey.Script))
copy(payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength:], coinbaseData.ScriptPublicKey.Script)
copy(payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey:], coinbaseData.ExtraData)
return payload, nil
}
// ExtractCoinbaseDataAndBlueScore deserializes the coinbase payload to its component (scriptPubKey and extra data).
func (c *coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64,
coinbaseData *externalapi.DomainCoinbaseData, err error) {
minLength := uint64Len + lengthOfVersionScriptPubKey + lengthOfscriptPubKeyLength
if len(coinbaseTx.Payload) < minLength {
return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen,
"coinbase payload is less than the minimum length of %d", minLength)
}
blueScore = binary.LittleEndian.Uint64(coinbaseTx.Payload[:uint64Len])
scriptPubKeyVersion := uint16(coinbaseTx.Payload[uint64Len])
scriptPubKeyScriptLength := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey]
if scriptPubKeyScriptLength > c.coinbasePayloadScriptPublicKeyMaxLength {
return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+
"longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength)
}
if len(coinbaseTx.Payload) < minLength+int(scriptPubKeyScriptLength) {
return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen,
"coinbase payload doesn't have enough bytes to contain a script public key of %d bytes", scriptPubKeyScriptLength)
}
scriptPubKeyScript := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength : uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptPubKeyScriptLength]
return blueScore, &externalapi.DomainCoinbaseData{
ScriptPublicKey: &externalapi.ScriptPublicKey{Script: scriptPubKeyScript, Version: scriptPubKeyVersion},
ExtraData: coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptPubKeyScriptLength:],
}, nil
}