From 369a3bac091ac1a70400b79c6cdcce2e6a3ebe5c Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 14 Jul 2021 14:21:57 +0300 Subject: [PATCH] Limit block mass instead of merge set limit + Introduce SigOpCount to TransactionInput (#1790) * Update constants * Add to transaction SigOpCount * Update mass calculation, and move it from InContext to InIsolation * Update block validation accordingly * Add SigOpCount validation during TransactionInContext * Remove checking of mass vs maxMassAcceptedByBlock from consensusStateManager * Update mining manager with latest changes * Add SigOpCount to MsgTx.Copy() * Fix initTestTransactionAcceptanceDataForClone * Fix all tests in transaction_equal_clone_test.go * Fix TestBlockMass * Fix tests in transactionvalidator package * Add SigOpCount to sighash * Fix TestPruningDepth * Fix problems in libkaspawalelt * Fix integration tests * Fix CalculateSignatureHash tests * Remove remaining places talking about block size * Add sanity check to checkBlockMass to make sure all transactions have their mass filled * always add own sigOpCount to sigHash * Update protowire/rpc.md * Start working on removing any remaining reference to block/tx size * Update rpc transaction verbose data to include mass rather then size * Convert verboseData and block size check to mass * Remove remaining usages of tx size in mempool * Move transactionEstimatedSerializedSize to transactionvalidator * Add PopulateMass to fakeRelayInvsContext * Move PopulateMass to beggining of ValidateAndInsertTransaction + fix in it * Assign mass a new number for backward-compatibility --- app/appmessage/domainconverters.go | 5 + app/appmessage/p2p_msgtx.go | 5 +- app/appmessage/p2p_msgtx_test.go | 2 +- app/appmessage/rpc_submit_transaction.go | 3 +- .../flows/testing/handle_relay_invs_test.go | 4 + app/rpc/rpccontext/verbosedata.go | 4 +- .../protoserialization/wallet.pb.go | 20 +++- .../protoserialization/wallet.proto | 3 +- .../serialization/serialization.go | 9 +- cmd/kaspawallet/libkaspawallet/sign.go | 1 + domain/consensus/consensus.go | 7 +- .../database/serialization/dbobjects.pb.go | 12 +- .../database/serialization/dbobjects.proto | 1 + .../database/serialization/transaction.go | 5 +- domain/consensus/factory.go | 10 +- .../model/acceptancedata_equal_clone_test.go | 19 ++- .../consensus/model/externalapi/consensus.go | 1 + .../model/externalapi/transaction.go | 8 +- .../transaction_equal_clone_test.go | 62 ++++++++++ ...nterface_processes_transactionvalidator.go | 3 +- .../processes/blockbuilder/block_builder.go | 2 +- .../blockprocessor/validateandinsertblock.go | 1 - .../blockvalidator/block_body_in_isolation.go | 31 ++--- .../block_body_in_isolation_test.go | 20 ++-- .../blockvalidator/blockvalidator.go | 8 +- .../calculate_past_utxo.go | 31 +---- .../consensus_state_manager.go | 23 ++-- .../import_pruning_utxo_set.go | 2 +- .../verify_and_build_utxo.go | 4 +- .../processes/transactionvalidator/mass.go | 106 ++++++++++++----- .../transaction_in_context.go | 30 ++++- .../transaction_in_isolation.go | 1 + .../transaction_in_isolation_test.go | 7 +- .../transactionvalidator_test.go | 60 ++++++++-- domain/consensus/pruning_test.go | 8 +- domain/consensus/ruleerrors/rule_error.go | 7 +- .../calculate_signature_hash.go | 22 ++++ .../calculate_signature_hash_test.go | 112 +++++++++--------- .../transaction_estimated_size.go | 65 ---------- domain/consensus/utils/txscript/script.go | 8 +- domain/dagconfig/consensus_defaults.go | 35 +++--- domain/dagconfig/params.go | 19 +-- domain/miningmanager/factory.go | 2 +- .../mempool/check_transaction_standard.go | 32 +++-- .../check_transaction_standard_test.go | 6 +- domain/miningmanager/mempool/config.go | 12 +- domain/miningmanager/mempool/orphan_pool.go | 10 +- .../validate_and_insert_transaction.go | 3 + .../mempool/validate_transaction.go | 7 -- infrastructure/config/network.go | 11 +- .../grpcserver/protowire/messages.pb.go | 7 +- .../grpcserver/protowire/messages_grpc.pb.go | 47 ++------ .../server/grpcserver/protowire/p2p.pb.go | 21 +++- .../server/grpcserver/protowire/p2p.proto | 1 + .../grpcserver/protowire/p2p_transaction.go | 10 +- .../server/grpcserver/protowire/rpc.md | 2 + .../server/grpcserver/protowire/rpc.pb.go | 31 +++-- .../server/grpcserver/protowire/rpc.proto | 3 +- .../protowire/rpc_submit_transaction.go | 9 +- testing/integration/tx_relay_test.go | 2 +- testing/integration/utxo_index_test.go | 2 +- 61 files changed, 590 insertions(+), 414 deletions(-) delete mode 100644 domain/consensus/utils/estimatedsize/transaction_estimated_size.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 59fdb93bf..c74bd8bf9 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -2,6 +2,7 @@ package appmessage import ( "encoding/hex" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" @@ -100,6 +101,7 @@ func domainTransactionInputToTxIn(domainTransactionInput *externalapi.DomainTran PreviousOutpoint: *domainOutpointToOutpoint(domainTransactionInput.PreviousOutpoint), SignatureScript: domainTransactionInput.SignatureScript, Sequence: domainTransactionInput.Sequence, + SigOpCount: domainTransactionInput.SigOpCount, } } @@ -148,6 +150,7 @@ func txInToDomainTransactionInput(txIn *TxIn) *externalapi.DomainTransactionInpu return &externalapi.DomainTransactionInput{ PreviousOutpoint: *outpointToDomainOutpoint(&txIn.PreviousOutpoint), //TODO SignatureScript: txIn.SignatureScript, + SigOpCount: txIn.SigOpCount, Sequence: txIn.Sequence, } } @@ -175,6 +178,7 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa PreviousOutpoint: *previousOutpoint, SignatureScript: signatureScript, Sequence: input.Sequence, + SigOpCount: input.SigOpCount, } } outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs)) @@ -253,6 +257,7 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio PreviousOutpoint: previousOutpoint, SignatureScript: signatureScript, Sequence: input.Sequence, + SigOpCount: input.SigOpCount, } } outputs := make([]*RPCTransactionOutput, len(transaction.Outputs)) diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 8cceb9867..2062f03c7 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -90,16 +90,18 @@ type TxIn struct { PreviousOutpoint Outpoint SignatureScript []byte Sequence uint64 + SigOpCount byte } // NewTxIn returns a new kaspa transaction input with the provided // previous outpoint point and signature script with a default sequence of // MaxTxInSequenceNum. -func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64) *TxIn { +func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64, sigOpCount byte) *TxIn { return &TxIn{ PreviousOutpoint: *prevOut, SignatureScript: signatureScript, Sequence: sequence, + SigOpCount: sigOpCount, } } @@ -206,6 +208,7 @@ func (msg *MsgTx) Copy() *MsgTx { PreviousOutpoint: newOutpoint, SignatureScript: newScript, Sequence: oldTxIn.Sequence, + SigOpCount: oldTxIn.SigOpCount, } // Finally, append this fully copied txin. diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index 3a6d3caad..a2d9bbc78 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -68,7 +68,7 @@ func TestTx(t *testing.T) { // Ensure we get the same transaction input back out. sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} - txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum) + txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum, 1) if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) { t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v", spew.Sprint(&txIn.PreviousOutpoint), diff --git a/app/appmessage/rpc_submit_transaction.go b/app/appmessage/rpc_submit_transaction.go index f56cefccb..a39e7e574 100644 --- a/app/appmessage/rpc_submit_transaction.go +++ b/app/appmessage/rpc_submit_transaction.go @@ -61,6 +61,7 @@ type RPCTransactionInput struct { PreviousOutpoint *RPCOutpoint SignatureScript string Sequence uint64 + SigOpCount byte VerboseData *RPCTransactionInputVerboseData } @@ -98,7 +99,7 @@ type RPCUTXOEntry struct { type RPCTransactionVerboseData struct { TransactionID string Hash string - Size uint64 + Mass uint64 BlockHash string BlockTime uint64 } diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 0d2e5a4e5..f26f430a3 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -130,6 +130,10 @@ type fakeRelayInvsContext struct { rwLock sync.RWMutex } +func (f *fakeRelayInvsContext) PopulateMass(*externalapi.DomainTransaction) { + panic("implement me") +} + func (f *fakeRelayInvsContext) DeleteStagingConsensus() error { panic("implement me") } diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index d790b52b6..66c7c69aa 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -10,7 +10,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/app/appmessage" @@ -114,10 +113,11 @@ func (ctx *Context) PopulateTransactionWithVerboseData( return err } + ctx.Domain.Consensus().PopulateMass(domainTransaction) transaction.VerboseData = &appmessage.RPCTransactionVerboseData{ TransactionID: consensushashing.TransactionID(domainTransaction).String(), Hash: consensushashing.TransactionHash(domainTransaction).String(), - Size: estimatedsize.TransactionEstimatedSerializedSize(domainTransaction), + Mass: domainTransaction.Mass, } if domainBlockHeader != nil { transaction.VerboseData.BlockHash = consensushashing.HeaderHash(domainBlockHeader).String() diff --git a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go index 7ae90195f..5dc67cc97 100644 --- a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go +++ b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go @@ -89,7 +89,7 @@ type PartiallySignedInput struct { PrevOutput *TransactionOutput `protobuf:"bytes,2,opt,name=prevOutput,proto3" json:"prevOutput,omitempty"` MinimumSignatures uint32 `protobuf:"varint,3,opt,name=minimumSignatures,proto3" json:"minimumSignatures,omitempty"` PubKeySignaturePairs []*PubKeySignaturePair `protobuf:"bytes,4,rep,name=pubKeySignaturePairs,proto3" json:"pubKeySignaturePairs,omitempty"` - DerivationPath string `protobuf:"bytes,5,opt,name=DerivationPath,proto3" json:"DerivationPath,omitempty"` + DerivationPath string `protobuf:"bytes,5,opt,name=derivationPath,proto3" json:"derivationPath,omitempty"` } func (x *PartiallySignedInput) Reset() { @@ -364,6 +364,7 @@ type TransactionInput struct { PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + SigOpCount uint32 `protobuf:"varint,4,opt,name=sigOpCount,proto3" json:"sigOpCount,omitempty"` } func (x *TransactionInput) Reset() { @@ -419,6 +420,13 @@ func (x *TransactionInput) GetSequence() uint64 { return 0 } +func (x *TransactionInput) GetSigOpCount() uint32 { + if x != nil { + return x.SigOpCount + } + return 0 +} + type Outpoint struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -664,9 +672,9 @@ var file_wallet_proto_rawDesc = []byte{ 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x14, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x44, 0x65, 0x72, 0x69, + 0x75, 0x72, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, + 0x52, 0x0e, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x22, 0x5b, 0x0a, 0x13, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -695,7 +703,7 @@ var file_wallet_proto_rawDesc = []byte{ 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x64, 0x22, 0xc2, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x48, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, @@ -705,7 +713,9 @@ var file_wallet_proto_rawDesc = []byte{ 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x69, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x4f, + 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x69, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, diff --git a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.proto b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.proto index 6f08d89f8..72be9a743 100644 --- a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.proto +++ b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.proto @@ -13,7 +13,7 @@ message PartiallySignedInput{ TransactionOutput prevOutput = 2; uint32 minimumSignatures = 3; repeated PubKeySignaturePair pubKeySignaturePairs = 4; - string DerivationPath = 5; + string derivationPath = 5; } message PubKeySignaturePair{ @@ -39,6 +39,7 @@ message TransactionInput{ Outpoint previousOutpoint = 1; bytes signatureScript = 2; uint64 sequence = 3; + uint32 sigOpCount = 4; } message Outpoint{ diff --git a/cmd/kaspawallet/libkaspawallet/serialization/serialization.go b/cmd/kaspawallet/libkaspawallet/serialization/serialization.go index 044b4c9a4..3abdaef4a 100644 --- a/cmd/kaspawallet/libkaspawallet/serialization/serialization.go +++ b/cmd/kaspawallet/libkaspawallet/serialization/serialization.go @@ -1,12 +1,13 @@ package serialization import ( + "math" + "github.com/golang/protobuf/proto" "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization/protoserialization" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/pkg/errors" - "math" ) // PartiallySignedTransaction is a type that is intended @@ -190,6 +191,10 @@ func transactionToProto(tx *externalapi.DomainTransaction) *protoserialization.T } func transactionInputFromProto(protoInput *protoserialization.TransactionInput) (*externalapi.DomainTransactionInput, error) { + if protoInput.SigOpCount > math.MaxUint8 { + return nil, errors.New("TransactionInput SigOpCount > math.MaxUint8") + } + outpoint, err := outpointFromProto(protoInput.PreviousOutpoint) if err != nil { return nil, err @@ -199,6 +204,7 @@ func transactionInputFromProto(protoInput *protoserialization.TransactionInput) PreviousOutpoint: *outpoint, SignatureScript: protoInput.SignatureScript, Sequence: protoInput.Sequence, + SigOpCount: byte(protoInput.SigOpCount), }, nil } @@ -207,6 +213,7 @@ func transactionInputToProto(input *externalapi.DomainTransactionInput) *protose PreviousOutpoint: outpointToProto(&input.PreviousOutpoint), SignatureScript: input.SignatureScript, Sequence: input.Sequence, + SigOpCount: uint32(input.SigOpCount), } } diff --git a/cmd/kaspawallet/libkaspawallet/sign.go b/cmd/kaspawallet/libkaspawallet/sign.go index 839b63695..5bef3bf08 100644 --- a/cmd/kaspawallet/libkaspawallet/sign.go +++ b/cmd/kaspawallet/libkaspawallet/sign.go @@ -58,6 +58,7 @@ func sign(params *dagconfig.Params, mnemonic string, partiallySignedTransaction false, // This is a fake value, because it's irrelevant for the signature 0, // This is a fake value, because it's irrelevant for the signature ) + partiallySignedTransaction.Tx.Inputs[i].SigOpCount = byte(len(partiallySignedInput.PubKeySignaturePairs)) } signed := false diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 9d7647957..60d48e2f4 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -96,8 +96,7 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction if err != nil { return err } - - return s.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + return s.transactionValidator.ValidateTransactionInContextAndPopulateFee( stagingArea, transaction, model.VirtualBlockHash, virtualSelectedParentMedianTime) } @@ -556,3 +555,7 @@ func (s *consensus) EstimateNetworkHashesPerSecond(startHash *externalapi.Domain return s.difficultyManager.EstimateNetworkHashesPerSecond(startHash, windowSize) } + +func (s *consensus) PopulateMass(transaction *externalapi.DomainTransaction) { + s.transactionValidator.PopulateMass(transaction) +} diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 5b0a3ea57..113d77304 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -333,6 +333,7 @@ type DbTransactionInput struct { PreviousOutpoint *DbOutpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + SigOpCount uint32 `protobuf:"varint,4,opt,name=sigOpCount,proto3" json:"sigOpCount,omitempty"` } func (x *DbTransactionInput) Reset() { @@ -388,6 +389,13 @@ func (x *DbTransactionInput) GetSequence() uint64 { return 0 } +func (x *DbTransactionInput) GetSigOpCount() uint32 { + if x != nil { + return x.SigOpCount + } + return 0 +} + type DbOutpoint struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1664,7 +1672,7 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xa1, 0x01, 0x0a, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xc1, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x45, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, @@ -1675,6 +1683,8 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x68, 0x0a, 0x0a, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x44, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index fb59c0842..c09e3e55d 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -37,6 +37,7 @@ message DbTransactionInput { DbOutpoint previousOutpoint = 1; bytes signatureScript = 2; uint64 sequence = 3; + uint32 sigOpCount = 4; } message DbOutpoint { diff --git a/domain/consensus/database/serialization/transaction.go b/domain/consensus/database/serialization/transaction.go index 92b10fa4a..42d8fc740 100644 --- a/domain/consensus/database/serialization/transaction.go +++ b/domain/consensus/database/serialization/transaction.go @@ -1,9 +1,10 @@ package serialization import ( + "math" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" - "math" ) // DomainTransactionToDbTransaction converts DomainTransaction to DbTransaction @@ -14,6 +15,7 @@ func DomainTransactionToDbTransaction(domainTransaction *externalapi.DomainTrans PreviousOutpoint: DomainOutpointToDbOutpoint(&domainTransactionInput.PreviousOutpoint), SignatureScript: domainTransactionInput.SignatureScript, Sequence: domainTransactionInput.Sequence, + SigOpCount: uint32(domainTransactionInput.SigOpCount), } } @@ -54,6 +56,7 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap PreviousOutpoint: *domainPreviousOutpoint, SignatureScript: dbTransactionInput.SignatureScript, Sequence: dbTransactionInput.Sequence, + SigOpCount: byte(dbTransactionInput.SigOpCount), } } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index f9ab4d48b..e744610fe 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,13 +1,14 @@ package consensus import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/prefixmanager/prefix" - "github.com/pkg/errors" "io/ioutil" "os" "sync" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/prefixmanager/prefix" + "github.com/pkg/errors" + consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore" @@ -231,7 +232,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas config.SkipProofOfWork, genesisHash, config.EnableNonNativeSubnetworks, - config.MaxBlockSize, + config.MaxBlockMass, config.MergeSetSizeLimit, config.MaxBlockParents, config.TimestampDeviationTolerance, @@ -259,7 +260,6 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas consensusStateManager, err := consensusstatemanager.New( dbManager, config.PruningDepth(), - config.MaxMassAcceptedByBlock, config.MaxBlockParents, config.MergeSetSizeLimit, genesisHash, diff --git a/domain/consensus/model/acceptancedata_equal_clone_test.go b/domain/consensus/model/acceptancedata_equal_clone_test.go index 262767a4b..c7143172d 100644 --- a/domain/consensus/model/acceptancedata_equal_clone_test.go +++ b/domain/consensus/model/acceptancedata_equal_clone_test.go @@ -9,7 +9,6 @@ import ( ) func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAcceptanceData { - tests := []*externalapi.TransactionAcceptanceData{ { &externalapi.DomainTransaction{ @@ -18,6 +17,7 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -62,6 +62,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -91,6 +92,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -119,6 +121,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -147,6 +150,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -176,6 +180,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -206,6 +211,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -311,6 +317,7 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -358,6 +365,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -390,6 +398,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -422,6 +431,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -454,6 +464,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -487,6 +498,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -590,6 +602,7 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -639,6 +652,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -671,6 +685,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -703,6 +718,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -735,6 +751,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index ce96d2b3f..a300166a5 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -35,4 +35,5 @@ type Consensus interface { GetHeadersSelectedTip() (*DomainHash, error) Anticone(blockHash *DomainHash) ([]*DomainHash, error) EstimateNetworkHashesPerSecond(startHash *DomainHash, windowSize int) (uint64, error) + PopulateMass(transaction *DomainTransaction) } diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 159dabb38..33fd79203 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -131,13 +131,14 @@ type DomainTransactionInput struct { PreviousOutpoint DomainOutpoint SignatureScript []byte Sequence uint64 + SigOpCount byte UTXOEntry UTXOEntry } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ = &DomainTransactionInput{DomainOutpoint{}, []byte{}, 0, nil} +var _ = &DomainTransactionInput{DomainOutpoint{}, []byte{}, 0, 0, nil} // Equal returns whether input equals to other func (input *DomainTransactionInput) Equal(other *DomainTransactionInput) bool { @@ -157,6 +158,10 @@ func (input *DomainTransactionInput) Equal(other *DomainTransactionInput) bool { return false } + if input.SigOpCount != other.SigOpCount { + return false + } + if input.UTXOEntry != nil && other.UTXOEntry != nil && !input.UTXOEntry.Equal(other.UTXOEntry) { panic(errors.New("identical inputs should always have the same UTXO entry")) } @@ -173,6 +178,7 @@ func (input *DomainTransactionInput) Clone() *DomainTransactionInput { PreviousOutpoint: *input.PreviousOutpoint.Clone(), SignatureScript: signatureScriptClone, Sequence: input.Sequence, + SigOpCount: input.SigOpCount, UTXOEntry: input.UTXOEntry, } } diff --git a/domain/consensus/model/externalapi/transaction_equal_clone_test.go b/domain/consensus/model/externalapi/transaction_equal_clone_test.go index 9511857a2..ec23162e8 100644 --- a/domain/consensus/model/externalapi/transaction_equal_clone_test.go +++ b/domain/consensus/model/externalapi/transaction_equal_clone_test.go @@ -71,6 +71,7 @@ func initTestBaseTransaction() *externalapi.DomainTransaction { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -99,6 +100,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}, //Changed @@ -123,6 +125,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -147,6 +150,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -171,6 +175,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -196,6 +201,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -221,6 +227,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -245,6 +252,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -268,6 +276,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -291,6 +300,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -314,11 +324,13 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, {externalapi.DomainOutpoint{ *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -342,6 +354,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -366,6 +379,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -386,6 +400,31 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed sequence + 1, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + []byte{0x01}, + 0, + 1, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + 3, // Changed SigOpCount utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), @@ -410,6 +449,7 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, @@ -442,6 +482,7 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), @@ -556,6 +597,7 @@ func initTestBaseDomainTransactionInput() *externalapi.DomainTransactionInput { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), } return basetxInput @@ -567,6 +609,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: true, @@ -575,6 +618,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, false, 2), // Changed }, expectsPanic: true, @@ -583,6 +627,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, nil, // Changed }, expectedResult: true, @@ -591,6 +636,16 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed + 1, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), + 5, // Changed utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, @@ -599,6 +654,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3, 4}, // Changed uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, @@ -607,6 +663,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, @@ -615,6 +672,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(2 /* Changed */, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), // Changed }, expectedResult: false, @@ -623,6 +681,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(3 /* Changed */, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 3), // Changed }, expectedResult: false, @@ -640,18 +699,21 @@ func initTestDomainTransactionInputForClone() []*externalapi.DomainTransactionIn externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), + 1, utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }} return txInput diff --git a/domain/consensus/model/interface_processes_transactionvalidator.go b/domain/consensus/model/interface_processes_transactionvalidator.go index e59821c2f..7964945dd 100644 --- a/domain/consensus/model/interface_processes_transactionvalidator.go +++ b/domain/consensus/model/interface_processes_transactionvalidator.go @@ -10,6 +10,7 @@ type TransactionValidator interface { ValidateTransactionInIsolation(transaction *externalapi.DomainTransaction) error ValidateTransactionInContextIgnoringUTXO(stagingArea *StagingArea, tx *externalapi.DomainTransaction, povBlockHash *externalapi.DomainHash) error - ValidateTransactionInContextAndPopulateMassAndFee(stagingArea *StagingArea, + ValidateTransactionInContextAndPopulateFee(stagingArea *StagingArea, tx *externalapi.DomainTransaction, povBlockHash *externalapi.DomainHash, selectedParentMedianTime int64) error + PopulateMass(transaction *externalapi.DomainTransaction) } diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 95f6ee027..38cf02b3c 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -155,7 +155,7 @@ func (bb *blockBuilder) validateTransaction( return err } - return bb.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + return bb.transactionValidator.ValidateTransactionInContextAndPopulateFee( stagingArea, transaction, model.VirtualBlockHash, virtualSelectedParentMedianTime) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 45792d732..3509028c5 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -60,7 +60,6 @@ func (bp *blockProcessor) setBlockStatusAfterBlockValidation( } func (bp *blockProcessor) updateVirtualAcceptanceDataAfterImportingPruningPoint(stagingArea *model.StagingArea) error { - _, virtualAcceptanceData, virtualMultiset, err := bp.consensusStateManager.CalculatePastUTXOAndAcceptanceData(stagingArea, model.VirtualBlockHash) if err != nil { diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index f9cf57562..7f319af08 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -5,7 +5,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" @@ -34,11 +33,6 @@ func (v *blockValidator) ValidateBodyInIsolation(stagingArea *model.StagingArea, return err } - err = v.checkBlockSize(block) - if err != nil { - return err - } - err = v.checkBlockContainsAtLeastOneTransaction(block) if err != nil { return err @@ -69,6 +63,11 @@ func (v *blockValidator) ValidateBodyInIsolation(stagingArea *model.StagingArea, return err } + err = v.checkBlockMass(block) + if err != nil { + return err + } + err = v.checkBlockDuplicateTransactions(block) if err != nil { return err @@ -215,16 +214,18 @@ func (v *blockValidator) validateGasLimit(block *externalapi.DomainBlock) error return nil } -func (v *blockValidator) checkBlockSize(block *externalapi.DomainBlock) error { - size := uint64(0) - size += v.headerEstimatedSerializedSize(block.Header) +func (v *blockValidator) checkBlockMass(block *externalapi.DomainBlock) error { + mass := uint64(0) + mass += v.headerEstimatedSerializedSize(block.Header) - for _, tx := range block.Transactions { - sizeBefore := size - size += estimatedsize.TransactionEstimatedSerializedSize(tx) - if size > v.maxBlockSize || size < sizeBefore { - return errors.Wrapf(ruleerrors.ErrBlockSizeTooHigh, "block excceeded the size limit of %d", - v.maxBlockSize) + for _, transaction := range block.Transactions { + v.transactionValidator.PopulateMass(transaction) + + massBefore := mass + mass += transaction.Mass + if mass > v.maxBlockMass || mass < massBefore { + return errors.Wrapf(ruleerrors.ErrBlockMassTooHigh, "block exceeded the mass limit of %d", + v.maxBlockMass) } } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index e0aa1bd60..f4a36f298 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -1027,17 +1027,16 @@ func TestCheckBlockHashMerkleRoot(t *testing.T) { }) } -func TestBlockSize(t *testing.T) { +func TestBlockMass(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) { - factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockSize") + tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockMass") if err != nil { t.Fatalf("Error setting up tc: %+v", err) } defer teardown(false) - block, _, err := initBlockWithInvalidBlockSize(consensusConfig, tc) + block, _, err := initBlockWithInvalidBlockMass(consensusConfig, tc) if err != nil { t.Fatalf("Error BuildBlockWithParents : %+v", err) } @@ -1046,14 +1045,14 @@ func TestBlockSize(t *testing.T) { tc.BlockStore().Stage(stagingArea, blockHash, block) err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash) - if err == nil || !errors.Is(err, ruleerrors.ErrBlockSizeTooHigh) { - t.Fatalf("ValidateBodyInIsolationTest: TestBlockSize:"+ - " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrBlockSizeTooHigh, err) + if err == nil || !errors.Is(err, ruleerrors.ErrBlockMassTooHigh) { + t.Fatalf("ValidateBodyInIsolationTest: TestBlockMass:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrBlockMassTooHigh, err) } }) } -func initBlockWithInvalidBlockSize(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) { +func initBlockWithInvalidBlockMass(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) { emptyCoinbase := externalapi.DomainCoinbaseData{ ScriptPublicKey: &externalapi.ScriptPublicKey{ Script: nil, @@ -1062,11 +1061,12 @@ func initBlockWithInvalidBlockSize(consensusConfig *consensus.Config, tc testapi } prevOutTxID := &externalapi.DomainTransactionID{} prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} - bigSignatureScript := bytes.Repeat([]byte("01"), 25000) + bigSignatureScript := bytes.Repeat([]byte("01"), 500000) txInput := externalapi.DomainTransactionInput{ PreviousOutpoint: prevOutPoint, SignatureScript: bigSignatureScript, Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 10, UTXOEntry: utxo.NewUTXOEntry( 100_000_000, &externalapi.ScriptPublicKey{}, @@ -1079,7 +1079,7 @@ func initBlockWithInvalidBlockSize(consensusConfig *consensus.Config, tc testapi Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, - Payload: []byte{0x01}, + Payload: []byte{}, } return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx}) diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 1fb52cc5b..ca272eb2f 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -1,12 +1,12 @@ package blockvalidator import ( - "github.com/kaspanet/kaspad/util/difficulty" "math/big" "time" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/util/difficulty" ) // blockValidator exposes a set of validation classes, after which @@ -17,7 +17,7 @@ type blockValidator struct { genesisHash *externalapi.DomainHash enableNonNativeSubnetworks bool powMaxBits uint32 - maxBlockSize uint64 + maxBlockMass uint64 mergeSetSizeLimit uint64 maxBlockParents model.KType timestampDeviationTolerance int @@ -48,7 +48,7 @@ func New(powMax *big.Int, skipPoW bool, genesisHash *externalapi.DomainHash, enableNonNativeSubnetworks bool, - maxBlockSize uint64, + maxBlockMass uint64, mergeSetSizeLimit uint64, maxBlockParents model.KType, timestampDeviationTolerance int, @@ -82,7 +82,7 @@ func New(powMax *big.Int, genesisHash: genesisHash, enableNonNativeSubnetworks: enableNonNativeSubnetworks, powMaxBits: difficulty.BigToCompact(powMax), - maxBlockSize: maxBlockSize, + maxBlockMass: maxBlockMass, mergeSetSizeLimit: mergeSetSizeLimit, maxBlockParents: maxBlockParents, diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index e67ed39d0..d8bcb6226 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -237,7 +237,7 @@ func (csm *consensusStateManager) maybeAcceptTransaction(stagingArea *model.Stag log.Tracef("Transaction %s is the coinbase of block %s", transactionID, blockHash) } else { log.Tracef("Validating transaction %s in block %s", transactionID, blockHash) - err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + err = csm.transactionValidator.ValidateTransactionInContextAndPopulateFee( stagingArea, transaction, blockHash, selectedParentPastMedianTime) if err != nil { if !errors.As(err, &(ruleerrors.RuleError{})) { @@ -249,14 +249,6 @@ func (csm *consensusStateManager) maybeAcceptTransaction(stagingArea *model.Stag return false, accumulatedMassBefore, nil } log.Tracef("Validation passed for transaction %s in block %s", transactionID, blockHash) - - log.Tracef("Check mass for transaction %s in block %s", transactionID, blockHash) - isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) - if !isAccepted { - log.Tracef("Transaction %s in block %s has too much mass, "+ - "and cannot be accepted", transactionID, blockHash) - return false, accumulatedMassBefore, nil - } } log.Tracef("Adding transaction %s in block %s to the accumulated diff", transactionID, blockHash) @@ -268,27 +260,6 @@ func (csm *consensusStateManager) maybeAcceptTransaction(stagingArea *model.Stag return true, accumulatedMassAfter, nil } -func (csm *consensusStateManager) checkTransactionMass(transaction *externalapi.DomainTransaction, accumulatedMassBefore uint64) ( - isAccepted bool, accumulatedMassAfter uint64) { - - transactionID := consensushashing.TransactionID(transaction) - log.Tracef("checkTransactionMass start for transaction %s", transactionID) - defer log.Tracef("checkTransactionMass end for transaction %s", transactionID) - - log.Tracef("Adding transaction %s with mass %d to the "+ - "so-far accumulated mass of %d", transactionID, transaction.Mass, accumulatedMassBefore) - accumulatedMassAfter = accumulatedMassBefore + transaction.Mass - log.Tracef("Accumulated mass including transaction %s: %d", transactionID, accumulatedMassAfter) - - // We could potentially overflow the accumulator so check for - // overflow as well. - if accumulatedMassAfter < transaction.Mass || accumulatedMassAfter > csm.maxMassAcceptedByBlock { - return false, 0 - } - - return true, accumulatedMassAfter -} - // RestorePastUTXOSetIterator restores the given block's UTXOSet iterator, and returns it as a externalapi.ReadOnlyUTXOSetIterator func (csm *consensusStateManager) RestorePastUTXOSetIterator(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) ( externalapi.ReadOnlyUTXOSetIterator, error) { diff --git a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go index dcc7f5746..6c0ce99f8 100644 --- a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go @@ -7,12 +7,11 @@ import ( // consensusStateManager manages the node's consensus state type consensusStateManager struct { - pruningDepth uint64 - maxMassAcceptedByBlock uint64 - maxBlockParents model.KType - mergeSetSizeLimit uint64 - genesisHash *externalapi.DomainHash - databaseContext model.DBManager + pruningDepth uint64 + maxBlockParents model.KType + mergeSetSizeLimit uint64 + genesisHash *externalapi.DomainHash + databaseContext model.DBManager ghostdagManager model.GHOSTDAGManager dagTopologyManager model.DAGTopologyManager @@ -46,7 +45,6 @@ type consensusStateManager struct { func New( databaseContext model.DBManager, pruningDepth uint64, - maxMassAcceptedByBlock uint64, maxBlockParents model.KType, mergeSetSizeLimit uint64, genesisHash *externalapi.DomainHash, @@ -77,12 +75,11 @@ func New( daaBlocksStore model.DAABlocksStore) (model.ConsensusStateManager, error) { csm := &consensusStateManager{ - pruningDepth: pruningDepth, - maxMassAcceptedByBlock: maxMassAcceptedByBlock, - maxBlockParents: maxBlockParents, - mergeSetSizeLimit: mergeSetSizeLimit, - genesisHash: genesisHash, - databaseContext: databaseContext, + pruningDepth: pruningDepth, + maxBlockParents: maxBlockParents, + mergeSetSizeLimit: mergeSetSizeLimit, + genesisHash: genesisHash, + databaseContext: databaseContext, ghostdagManager: ghostdagManager, dagTopologyManager: dagTopologyManager, diff --git a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go index 2f77eca78..0c4d18dcb 100644 --- a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go @@ -118,7 +118,7 @@ func (csm *consensusStateManager) importPruningPoint( continue } log.Tracef("Validating transaction %s and populating it with mass and fee", transactionID) - err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + err = csm.transactionValidator.ValidateTransactionInContextAndPopulateFee( stagingArea, transaction, newPruningPointHash, newPruningPointSelectedParentMedianTime) if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 28f4e0a0d..b9672356f 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -83,8 +83,8 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(stagi return err } - log.Tracef("Validating transaction %s and populating it with mass and fee", transactionID) - err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + log.Tracef("Validating transaction %s and populating it with fee", transactionID) + err = csm.transactionValidator.ValidateTransactionInContextAndPopulateFee( stagingArea, transaction, blockHash, selectedParentMedianTime) if err != nil { return err diff --git a/domain/consensus/processes/transactionvalidator/mass.go b/domain/consensus/processes/transactionvalidator/mass.go index 041537bf8..c4e4a7aaf 100644 --- a/domain/consensus/processes/transactionvalidator/mass.go +++ b/domain/consensus/processes/transactionvalidator/mass.go @@ -2,47 +2,99 @@ package transactionvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" ) -func (v *transactionValidator) transactionMassStandalonePart(tx *externalapi.DomainTransaction) uint64 { - size := estimatedsize.TransactionEstimatedSerializedSize(tx) +func (v *transactionValidator) PopulateMass(transaction *externalapi.DomainTransaction) { + if transaction.Mass != 0 { + return + } + transaction.Mass = v.transactionMass(transaction) +} +func (v *transactionValidator) transactionMass(transaction *externalapi.DomainTransaction) uint64 { + if transactionhelper.IsCoinBase(transaction) { + return 0 + } + + // calculate mass for size + size := transactionEstimatedSerializedSize(transaction) + massForSize := size * v.massPerTxByte + + // calculate mass for scriptPubKey totalScriptPubKeySize := uint64(0) - for _, output := range tx.Outputs { + for _, output := range transaction.Outputs { totalScriptPubKeySize += 2 //output.ScriptPublicKey.Version (uint16) totalScriptPubKeySize += uint64(len(output.ScriptPublicKey.Script)) } + massForScriptPubKey := totalScriptPubKeySize * v.massPerScriptPubKeyByte - return size*v.massPerTxByte + totalScriptPubKeySize*v.massPerScriptPubKeyByte + // calculate mass for SigOps + totalSigOpCount := uint64(0) + for _, input := range transaction.Inputs { + totalSigOpCount += uint64(input.SigOpCount) + } + massForSigOps := totalSigOpCount * v.massPerSigOp + + // Sum all components of mass + return massForSize + massForScriptPubKey + massForSigOps } -func (v *transactionValidator) transactionMass(tx *externalapi.DomainTransaction) (uint64, error) { +// transactionEstimatedSerializedSize is the estimated size of a transaction in some +// serialization. This has to be deterministic, but not necessarily accurate, since +// it's only used as the size component in the transaction and block mass limit +// calculation. +func transactionEstimatedSerializedSize(tx *externalapi.DomainTransaction) uint64 { if transactionhelper.IsCoinBase(tx) { - return 0, nil + return 0 } - - standaloneMass := v.transactionMassStandalonePart(tx) - sigOpsCount := uint64(0) - var missingOutpoints []*externalapi.DomainOutpoint + size := uint64(0) + size += 2 // Txn Version + size += 8 // number of inputs (uint64) for _, input := range tx.Inputs { - utxoEntry := input.UTXOEntry - if utxoEntry == nil { - missingOutpoints = append(missingOutpoints, &input.PreviousOutpoint) - continue - } - // Count the precise number of signature operations in the - // referenced public key script. - sigScript := input.SignatureScript - isP2SH := txscript.IsPayToScriptHash(utxoEntry.ScriptPublicKey()) - sigOpsCount += uint64(txscript.GetPreciseSigOpCount(sigScript, utxoEntry.ScriptPublicKey(), isP2SH)) - } - if len(missingOutpoints) > 0 { - return 0, ruleerrors.NewErrMissingTxOut(missingOutpoints) + size += transactionInputEstimatedSerializedSize(input) } - return standaloneMass + sigOpsCount*v.massPerSigOp, nil + size += 8 // number of outputs (uint64) + for _, output := range tx.Outputs { + size += TransactionOutputEstimatedSerializedSize(output) + } + + size += 8 // lock time (uint64) + size += externalapi.DomainSubnetworkIDSize + size += 8 // gas (uint64) + size += externalapi.DomainHashSize // payload hash + + size += 8 // length of the payload (uint64) + size += uint64(len(tx.Payload)) + + return size +} + +func transactionInputEstimatedSerializedSize(input *externalapi.DomainTransactionInput) uint64 { + size := uint64(0) + size += outpointEstimatedSerializedSize() + + size += 8 // length of signature script (uint64) + size += uint64(len(input.SignatureScript)) + + size += 8 // sequence (uint64) + return size +} + +func outpointEstimatedSerializedSize() uint64 { + size := uint64(0) + size += externalapi.DomainHashSize // ID + size += 4 // index (uint32) + return size +} + +// TransactionOutputEstimatedSerializedSize is the same as transactionEstimatedSerializedSize but for outputs only +func TransactionOutputEstimatedSerializedSize(output *externalapi.DomainTransactionOutput) uint64 { + size := uint64(0) + size += 8 // value (uint64) + size += 2 // output.ScriptPublicKey.Version (uint 16) + size += 8 // length of script public key (uint64) + size += uint64(len(output.ScriptPublicKey.Script)) + return size } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index 41dc53d2c..de8bc5761 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -65,11 +65,11 @@ func (v *transactionValidator) ValidateTransactionInContextIgnoringUTXO(stagingA return nil } -// ValidateTransactionInContextAndPopulateMassAndFee validates the transaction against its referenced UTXO, and -// populates its mass and fee fields. +// ValidateTransactionInContextAndPopulateFee validates the transaction against its referenced UTXO, and +// populates its fee field. // -// Note: if the function fails, there's no guarantee that the transaction mass and fee fields will remain unaffected. -func (v *transactionValidator) ValidateTransactionInContextAndPopulateMassAndFee(stagingArea *model.StagingArea, +// Note: if the function fails, there's no guarantee that the transaction fee field will remain unaffected. +func (v *transactionValidator) ValidateTransactionInContextAndPopulateFee(stagingArea *model.StagingArea, tx *externalapi.DomainTransaction, povBlockHash *externalapi.DomainHash, selectedParentMedianTime int64) error { err := v.checkTransactionCoinbaseMaturity(stagingArea, povBlockHash, tx) @@ -94,12 +94,12 @@ func (v *transactionValidator) ValidateTransactionInContextAndPopulateMassAndFee return err } - err = v.validateTransactionScripts(tx) + err = v.validateTransactionSigOpCounts(tx) if err != nil { return err } - tx.Mass, err = v.transactionMass(tx) + err = v.validateTransactionScripts(tx) if err != nil { return err } @@ -399,3 +399,21 @@ func (v *transactionValidator) sequenceLockActive(sequenceLock *sequenceLock, bl return true } + +func (v *transactionValidator) validateTransactionSigOpCounts(tx *externalapi.DomainTransaction) error { + for i, input := range tx.Inputs { + utxoEntry := input.UTXOEntry + + // Count the precise number of signature operations in the + // referenced public key script. + sigScript := input.SignatureScript + isP2SH := txscript.IsPayToScriptHash(utxoEntry.ScriptPublicKey()) + sigOpCount := txscript.GetPreciseSigOpCount(sigScript, utxoEntry.ScriptPublicKey(), isP2SH) + if sigOpCount != int(input.SigOpCount) { + return errors.Wrapf(ruleerrors.ErrWrongSigOpCount, + "input %d specifies SigOpCount %d while actual SigOpCount is %d", + i, input.SigOpCount, sigOpCount) + } + } + return nil +} diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index ed964c78f..1c41dff61 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" ) +// ValidateTransactionInIsolation validates the parts of the transaction that can be validated context-free func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.DomainTransaction) error { err := v.checkTransactionInputCount(tx) if err != nil { diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index 5e0cdb8f1..8327ab79a 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -20,10 +20,10 @@ type txSubnetworkData struct { payload []byte } -func TestValidateTransactionInIsolation(t *testing.T) { +func TestValidateTransactionInIsolationAndPopulateMass(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateTransactionInIsolation") + tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateTransactionInIsolationAndPopulateMass") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -111,7 +111,7 @@ func TestValidateTransactionInIsolation(t *testing.T) { err := tc.TransactionValidator().ValidateTransactionInIsolation(tx) if !errors.Is(err, test.expectedErr) { - t.Errorf("TestValidateTransactionInIsolation: '%s': unexpected error %+v", test.name, err) + t.Errorf("TestValidateTransactionInIsolationAndPopulateMass: '%s': unexpected error %+v", test.name, err) } } }) @@ -129,6 +129,7 @@ func createTxForTest(numInputs uint32, numOutputs uint32, outputValue uint64, su }, SignatureScript: []byte{}, Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, }) } diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go b/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go index 28bcf0669..cf28af586 100644 --- a/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go +++ b/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go @@ -32,7 +32,7 @@ func (mdf *mocPastMedianTimeManager) PastMedianTime(*model.StagingArea, *externa return mdf.pastMedianTimeForTest, nil } -func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { +func TestValidateTransactionInContextAndPopulateFee(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) { factory := consensus.NewFactory() @@ -42,7 +42,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { return pastMedianManager }) tc, tearDown, err := factory.NewTestConsensus(consensusConfig, - "TestValidateTransactionInContextAndPopulateMassAndFee") + "TestValidateTransactionInContextAndPopulateFee") if err != nil { t.Fatalf("Failed create a NewTestConsensus: %s", err) } @@ -76,6 +76,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { PreviousOutpoint: prevOutPoint, SignatureScript: []byte{}, Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, UTXOEntry: utxo.NewUTXOEntry( 100_000_000, // 1 KAS scriptPublicKey, @@ -86,6 +87,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { PreviousOutpoint: prevOutPoint, SignatureScript: []byte{}, Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, UTXOEntry: utxo.NewUTXOEntry( 100_000_000, // 1 KAS scriptPublicKey, @@ -96,6 +98,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { PreviousOutpoint: prevOutPoint, SignatureScript: []byte{}, Sequence: constants.SequenceLockTimeIsSeconds, + SigOpCount: 1, UTXOEntry: utxo.NewUTXOEntry( 100000000, // 1 KAS scriptPublicKey, @@ -106,12 +109,24 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { PreviousOutpoint: prevOutPoint, SignatureScript: []byte{}, Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, UTXOEntry: utxo.NewUTXOEntry( constants.MaxSompi, scriptPublicKey, true, uint64(5)), } + txInputWithBadSigOpCount := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: []byte{}, + Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 2, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, // 1 KAS + scriptPublicKey, + true, + uint64(5)), + } txOut := externalapi.DomainTransactionOutput{ Value: 100000000, // 1 KAS @@ -167,6 +182,13 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { SubnetworkID: subnetworks.SubnetworkIDRegistry, Gas: 0, LockTime: 0} + txWithBadSigOpCount := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInputWithBadSigOpCount}, + Outputs: []*externalapi.DomainTransactionOutput{&txOut}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} stagingArea := model.NewStagingArea() @@ -240,19 +262,27 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { isValid: false, expectedError: ruleerrors.ErrScriptValidation, }, + { // the SigOpCount in the input is wrong, and hence invalid + name: "checkTransactionSigOpCounts", + tx: &txWithBadSigOpCount, + povBlockHash: povBlockHash, + selectedParentMedianTime: 1, + isValid: false, + expectedError: ruleerrors.ErrWrongSigOpCount, + }, } for _, test := range tests { - err := tc.TransactionValidator().ValidateTransactionInContextAndPopulateMassAndFee(stagingArea, test.tx, test.povBlockHash, test.selectedParentMedianTime) + err := tc.TransactionValidator().ValidateTransactionInContextAndPopulateFee(stagingArea, test.tx, test.povBlockHash, test.selectedParentMedianTime) if test.isValid { if err != nil { - t.Fatalf("Unexpected error on TestValidateTransactionInContextAndPopulateMassAndFee"+ + t.Fatalf("Unexpected error on TestValidateTransactionInContextAndPopulateFee"+ " on test '%v': %+v", test.name, err) } } else { if err == nil || !errors.Is(err, test.expectedError) { - t.Fatalf("TestValidateTransactionInContextAndPopulateMassAndFee: test %v:"+ + t.Fatalf("TestValidateTransactionInContextAndPopulateFee: test %v:"+ " Unexpected error: Expected to: %v, but got : %+v", test.name, test.expectedError, err) } } @@ -335,16 +365,18 @@ func TestSigningTwoInputs(t *testing.T) { TransactionID: *consensushashing.TransactionID(block2.Transactions[0]), Index: 0, }, - Sequence: constants.MaxTxInSequenceNum, - UTXOEntry: utxo.NewUTXOEntry(block2TxOut.Value, block2TxOut.ScriptPublicKey, true, 0), + Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, + UTXOEntry: utxo.NewUTXOEntry(block2TxOut.Value, block2TxOut.ScriptPublicKey, true, 0), }, { PreviousOutpoint: externalapi.DomainOutpoint{ TransactionID: *consensushashing.TransactionID(block3.Transactions[0]), Index: 0, }, - Sequence: constants.MaxTxInSequenceNum, - UTXOEntry: utxo.NewUTXOEntry(block3TxOut.Value, block3TxOut.ScriptPublicKey, true, 0), + Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, + UTXOEntry: utxo.NewUTXOEntry(block3TxOut.Value, block3TxOut.ScriptPublicKey, true, 0), }, }, Outputs: []*externalapi.DomainTransactionOutput{{ @@ -459,16 +491,18 @@ func TestSigningTwoInputsECDSA(t *testing.T) { TransactionID: *consensushashing.TransactionID(block2.Transactions[0]), Index: 0, }, - Sequence: constants.MaxTxInSequenceNum, - UTXOEntry: utxo.NewUTXOEntry(block2TxOut.Value, block2TxOut.ScriptPublicKey, true, 0), + Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, + UTXOEntry: utxo.NewUTXOEntry(block2TxOut.Value, block2TxOut.ScriptPublicKey, true, 0), }, { PreviousOutpoint: externalapi.DomainOutpoint{ TransactionID: *consensushashing.TransactionID(block3.Transactions[0]), Index: 0, }, - Sequence: constants.MaxTxInSequenceNum, - UTXOEntry: utxo.NewUTXOEntry(block3TxOut.Value, block3TxOut.ScriptPublicKey, true, 0), + Sequence: constants.MaxTxInSequenceNum, + SigOpCount: 1, + UTXOEntry: utxo.NewUTXOEntry(block3TxOut.Value, block3TxOut.ScriptPublicKey, true, 0), }, }, Outputs: []*externalapi.DomainTransactionOutput{{ diff --git a/domain/consensus/pruning_test.go b/domain/consensus/pruning_test.go index bab0800be..6deee273f 100644 --- a/domain/consensus/pruning_test.go +++ b/domain/consensus/pruning_test.go @@ -10,10 +10,10 @@ import ( func TestPruningDepth(t *testing.T) { expectedResult := map[string]uint64{ - dagconfig.MainnetParams.Name: 244838, - dagconfig.TestnetParams.Name: 244838, - dagconfig.DevnetParams.Name: 244838, - dagconfig.SimnetParams.Name: 192038, + dagconfig.MainnetParams.Name: 185798, + dagconfig.TestnetParams.Name: 185798, + dagconfig.DevnetParams.Name: 185798, + dagconfig.SimnetParams.Name: 132998, } testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) { expected, found := expectedResult[consensusConfig.Name] diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 0d7e42efe..c19f7318e 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -139,6 +139,9 @@ var ( // a Payload ErrInvalidPayload = newRuleError("ErrInvalidPayload") + // ErrWrongSigOpCount transaction input specifies an incorrect SigOpCount + ErrWrongSigOpCount = newRuleError("ErrWrongSigOpCount") + // ErrSubnetwork indicates that a block doesn't adhere to the subnetwork // registry rules ErrSubnetworkRegistry = newRuleError("ErrSubnetworkRegistry") @@ -161,9 +164,9 @@ var ( // In the same block ErrChainedTransactions = newRuleError("ErrChainedTransactions") - // ErrBlockSizeTooHigh indicates the size of a block exceeds the maximum + // ErrBlockMassTooHigh indicates the mass of a block exceeds the maximum // allowed limits. - ErrBlockSizeTooHigh = newRuleError("ErrBlockSizeTooHigh") + ErrBlockMassTooHigh = newRuleError("ErrBlockMassTooHigh") ErrKnownInvalid = newRuleError("ErrKnownInvalid") diff --git a/domain/consensus/utils/consensushashing/calculate_signature_hash.go b/domain/consensus/utils/consensushashing/calculate_signature_hash.go index 9be79e73d..a90dda5db 100644 --- a/domain/consensus/utils/consensushashing/calculate_signature_hash.go +++ b/domain/consensus/utils/consensushashing/calculate_signature_hash.go @@ -53,6 +53,7 @@ func (sht SigHashType) isSigHashAnyOneCanPay() bool { type SighashReusedValues struct { previousOutputsHash *externalapi.DomainHash sequencesHash *externalapi.DomainHash + sigOpCountsHash *externalapi.DomainHash outputsHash *externalapi.DomainHash payloadHash *externalapi.DomainHash } @@ -102,6 +103,9 @@ func calculateSignatureHash(tx *externalapi.DomainTransaction, inputIndex int, t sequencesHash := getSequencesHash(tx, hashType, reusedValues) infallibleWriteElement(hashWriter, sequencesHash) + sigOpCountsHash := getSigOpCountsHash(tx, hashType, reusedValues) + infallibleWriteElement(hashWriter, sigOpCountsHash) + hashOutpoint(hashWriter, txIn.PreviousOutpoint) infallibleWriteElement(hashWriter, prevScriptPublicKey.Version) @@ -111,6 +115,8 @@ func calculateSignatureHash(tx *externalapi.DomainTransaction, inputIndex int, t infallibleWriteElement(hashWriter, txIn.Sequence) + infallibleWriteElement(hashWriter, txIn.SigOpCount) + outputsHash := getOutputsHash(tx, inputIndex, hashType, reusedValues) infallibleWriteElement(hashWriter, outputsHash) @@ -159,6 +165,22 @@ func getSequencesHash(tx *externalapi.DomainTransaction, hashType SigHashType, r return reusedValues.sequencesHash } +func getSigOpCountsHash(tx *externalapi.DomainTransaction, hashType SigHashType, reusedValues *SighashReusedValues) *externalapi.DomainHash { + if hashType.isSigHashAnyOneCanPay() { + return externalapi.NewZeroHash() + } + + if reusedValues.sigOpCountsHash == nil { + hashWriter := hashes.NewTransactionSigningHashWriter() + for _, txIn := range tx.Inputs { + infallibleWriteElement(hashWriter, txIn.SigOpCount) + } + reusedValues.sigOpCountsHash = hashWriter.Finalize() + } + + return reusedValues.sigOpCountsHash +} + func getOutputsHash(tx *externalapi.DomainTransaction, inputIndex int, hashType SigHashType, reusedValues *SighashReusedValues) *externalapi.DomainHash { // SigHashNone: return zero-hash if hashType.isSigHashNone() { diff --git a/domain/consensus/utils/consensushashing/calculate_signature_hash_test.go b/domain/consensus/utils/consensushashing/calculate_signature_hash_test.go index 059f3bbbb..057d05961 100644 --- a/domain/consensus/utils/consensushashing/calculate_signature_hash_test.go +++ b/domain/consensus/utils/consensushashing/calculate_signature_hash_test.go @@ -108,86 +108,86 @@ func TestCalculateSignatureHashSchnorr(t *testing.T) { // sigHashAll {name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0, - expectedSignatureHash: "3e4a8effa6903dea5f762754ec410d732114ec2907e5bcbae7b6dd8d3f309a10"}, + expectedSignatureHash: "56071ab5533ce9635d2a65d911b15d50b5e5f3e3103797d53173188a11696962"}, {name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyInput(1), // should change the hash - expectedSignatureHash: "0bd2947383101f9708d94d5799626c69c1b8472d2de66523c90c4a674e99cc51"}, + expectedSignatureHash: "3ee15a1f5d3827b9c3bca740ebbe422a8d07fbde287944f855da26c06782d38b"}, {name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyOutput(1), // should change the hash - expectedSignatureHash: "ae69aa1372e958f069bf52d2628ead7ee789f195340b615ff0bcb6f01a995810"}, + expectedSignatureHash: "1794d1d074a587678174223788bea272d092a6155f031686b85caf11595ff6d8"}, {name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifySequence(1), // should change the hash - expectedSignatureHash: "51295575e7efc1fe1c2e741ade49089e3d780d15d26e9a0b18b3d90e35caf795"}, + expectedSignatureHash: "8c580bd47a220e4ab6f343dde74a23f9e4b3971b2b519b0ed0ad34d682aa85d3"}, {name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, + expectedSignatureHash: "94dbee595dcbac18cc2c158e67315dacfdfc4af9ab08713d41d3546076daeb5a"}, {name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(0), // should change the hash - expectedSignatureHash: "aeaa56f5bc99daea0be5ed4b047808ce0123a81ac89c6089b72fa7199f5cd1c6"}, + expectedSignatureHash: "29cca3e62ad1e7069ccb67a4589ad6858b741ecb2abd9d470d0ec72903467edc"}, {name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(1), // shouldn't change the hash - expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, + expectedSignatureHash: "94dbee595dcbac18cc2c158e67315dacfdfc4af9ab08713d41d3546076daeb5a"}, {name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, + expectedSignatureHash: "94dbee595dcbac18cc2c158e67315dacfdfc4af9ab08713d41d3546076daeb5a"}, // sigHashNone {name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0, - expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, + expectedSignatureHash: "af54114c72a3192d05cfa80fb4be60bad77fc484b0072798e5e264da692dc4db"}, {name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, + expectedSignatureHash: "af54114c72a3192d05cfa80fb4be60bad77fc484b0072798e5e264da692dc4db"}, {name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash - expectedSignatureHash: "72c07c152a3792fb863d2de219ab4e863fe6779dc970a5c3958e26b3a3b9f139"}, + expectedSignatureHash: "52b3888a3680c79712b53c4010b7cdebd158e09b7574d95b846ba9989946c38b"}, {name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, + expectedSignatureHash: "af54114c72a3192d05cfa80fb4be60bad77fc484b0072798e5e264da692dc4db"}, {name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "18eb79df328a516708f792cadfc4bf2be21b6add35fb6637a20347d532b1dce1"}, + expectedSignatureHash: "cf1fd4691c22a75011909e7444c0d9582610374f7eea3debc450bbe939862cac"}, {name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyAmountSpent(0), // should change the hash - expectedSignatureHash: "674a8e6effa0bbfdb3df3ca45a7b17ab695cc0f9b3e0519e5bff165de13604e2"}, + expectedSignatureHash: "f76731710af7731896e415d85da6518fa316cddebd8abcb4b2ee931679296a0a"}, {name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyScriptPublicKey(0), // should change the hash - expectedSignatureHash: "7a879d339c9b948c5264f1c0b8463f551221b2dcd575623f178cbbfcf7e01987"}, + expectedSignatureHash: "382e8196e1fe34ccc4c3004ad6e6d4c41b81b8a5dd6de24fe51065a1970ef00b"}, // sigHashSingle {name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0, - expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, + expectedSignatureHash: "80a8db8aa43c5cd5d067c69e32f998ac5c0820d89fcfda9beaf55c8df41c4c86"}, {name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(0), // should change the hash - expectedSignatureHash: "92189a32391ca50a454d1853efed55acb1c49993911a1201df9891c866c483ee"}, + expectedSignatureHash: "ca882be7c6c3ae37badda62c9277be0808160d65a6a89feb514e41ed7a9658f0"}, {name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, + expectedSignatureHash: "80a8db8aa43c5cd5d067c69e32f998ac5c0820d89fcfda9beaf55c8df41c4c86"}, {name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash - expectedSignatureHash: "765e2289df98b3a5269f112d4b36d57fe32c74d42e04a3046c6a3c8dd78a4121"}, + expectedSignatureHash: "7dec3b5b7b5ccd3f82f93c6c08cd05acecb970d4a4d127fcd87a11d7e0dd96e3"}, {name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, + expectedSignatureHash: "80a8db8aa43c5cd5d067c69e32f998ac5c0820d89fcfda9beaf55c8df41c4c86"}, {name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2, - expectedSignatureHash: "43de18c04d7fde81f49a40228d8730b4ceb0c66c77841c22622f59554769dd13"}, + expectedSignatureHash: "3c6daba7d6849df524517f505d6abb93e20930726f89b50416eb2b6d59f202c6"}, {name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "43de18c04d7fde81f49a40228d8730b4ceb0c66c77841c22622f59554769dd13"}, + expectedSignatureHash: "3c6daba7d6849df524517f505d6abb93e20930726f89b50416eb2b6d59f202c6"}, {name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "2e270f86fd68f780a5aa8d250364ab6786d990040268e5d561d09dde365dfab7"}, + expectedSignatureHash: "35d28b074df6959cbef5aca8923e53312db3a88aab0039bd0a6b2fe92dff5aa7"}, {name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2, - expectedSignatureHash: "afc05dd6b4a530cc3a4d7d23126548bd1f31c793e9282cbbfa27ff5566219501"}, + expectedSignatureHash: "26a05df8e562f5c43cacab9a8126ae2da77e2137f8c28d13a330cd3d2b37d56b"}, // subnetwork transaction {name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0, - expectedSignatureHash: "5a67423ee048e067b94e2d4fc2960f62eceff6aa8b6c5ad71e3b7b7e5ff6bad7"}, + expectedSignatureHash: "1529c132cad68a014b01bac39992462f8d6c9ba6a34382e0d1d3054232e46c54"}, {name: "subnetwork-all-modify-payload", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyPayload, // should change the hash - expectedSignatureHash: "0d3bc5914da8dc8df081945fea1255359f380ca9baa8b31dfb3657c1e3c6038a"}, + expectedSignatureHash: "0366d1f0ab7a2150cd1b80b8f8944e7f6a42a38b846f2610adc4106fe70696ec"}, {name: "subnetwork-all-modify-gas", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyGas, // should change the hash - expectedSignatureHash: "70abe9f947d0a0f5d735f9a063db8af41fe5902940f2693a1782119063097094"}, + expectedSignatureHash: "19054bbf6dc75936dd018983373afd623a292ad1f39774cd1783b58074c3caa7"}, {name: "subnetwork-all-subnetwork-id", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifySubnetworkID, // should change the hash - expectedSignatureHash: "571a0b7ea905b7a6ff7ab825b72d23f911bac0bfaa7c4c97a4887a3d090925d4"}, + expectedSignatureHash: "2fbfa5d3d24673b2e3530c3b268b58ecb6e7e34116d5c18849c27b0e7b6bfe4c"}, } for _, test := range tests { @@ -230,86 +230,86 @@ func TestCalculateSignatureHashECDSA(t *testing.T) { // sigHashAll {name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0, - expectedSignatureHash: "150a2bcd0296f76a3395a4a9982df46bf24ce93f955bc39c10ffc95b6c524eb3"}, + expectedSignatureHash: "ea7b79230b41f503baa6d3c14edf2d3e2cabc62db5b384bbac451a84c7a69694"}, {name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyInput(1), // should change the hash - expectedSignatureHash: "8fb5304e181b003e0c123ea6f6677abc3704feec47054e8a1c218b827bf57ca0"}, + expectedSignatureHash: "9ba940467c07b4254f913a95398dc6f9fac0915e0dfe9560c58dfc1f87977c08"}, {name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyOutput(1), // should change the hash - expectedSignatureHash: "180cb36454aa80822694decde4fc711104e35a4bddf92286a83877f2b8d0aabb"}, + expectedSignatureHash: "ba413a6ef1101c4a4995ac30a9013fe5591ef5f6dd8d7aabaa5dd8cb74d4d765"}, {name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifySequence(1), // should change the hash - expectedSignatureHash: "5b5f1c42a3c3c16bb4922777e2963c00e6a2cce39afa1980d2288053378f9632"}, + expectedSignatureHash: "a471958e25168ab6671a76629d6f83b7f197a22972b333ebfa55d62dcc0ef065"}, {name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, + expectedSignatureHash: "1113e57a0a188f1b9d0e07889792193af37374112874af681b3e36bee0627c1f"}, {name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(0), // should change the hash - expectedSignatureHash: "1208491d564c138d613f51b997394dbad23feca7c0ca88c7f36cdf6b9173327d"}, + expectedSignatureHash: "6cce1e9ac60a7921a08ced668c03f74d207df02064896e0beb46988a8d2c243d"}, {name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(1), // shouldn't change the hash - expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, + expectedSignatureHash: "1113e57a0a188f1b9d0e07889792193af37374112874af681b3e36bee0627c1f"}, {name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, + expectedSignatureHash: "1113e57a0a188f1b9d0e07889792193af37374112874af681b3e36bee0627c1f"}, // sigHashNone {name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0, - expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, + expectedSignatureHash: "609c6f87c2cf10938ad1f69ceb0a6bb726690169b5e45d7c5797a420d244da55"}, {name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, + expectedSignatureHash: "609c6f87c2cf10938ad1f69ceb0a6bb726690169b5e45d7c5797a420d244da55"}, {name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash - expectedSignatureHash: "57d76e2568cd3fc3426b4f8836fe900a2d20e740fad744949126651fd549f75e"}, + expectedSignatureHash: "155e020f420fdaf62b31ccb3a13b6cb684c3db9ff85fc7062bb7e6a0653c7057"}, {name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, + expectedSignatureHash: "609c6f87c2cf10938ad1f69ceb0a6bb726690169b5e45d7c5797a420d244da55"}, {name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "ef97a0f89d623302619f9aa2a00fce1522e72d4d255e6c6d3ed225ffc02f38ff"}, + expectedSignatureHash: "3ee6c91cbbc998c52c02cad43b4a28743d6e96c9422393de69a0e15e08f470fb"}, {name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyAmountSpent(0), // should change the hash - expectedSignatureHash: "043a2a943f02607be126ac6609ab2324aae389d784a4147f27101e7da379311a"}, + expectedSignatureHash: "36e54667d08987a5d28d2124e7277ba5c2e93a9b8b9a7392bb7a57f1637edf76"}, {name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyScriptPublicKey(0), // should change the hash - expectedSignatureHash: "f2cd43d0d047cdcfbf8b6e12a86cfbf250f1e2c34dc5e631675a5f5b867bd9e6"}, + expectedSignatureHash: "bdce98b53163b42175f4e885f50e8a44821159fc05d7756e3870c5f91df2be2f"}, // sigHashSingle {name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0, - expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, + expectedSignatureHash: "354c6ac137e5a3d05e85e9740039909202c20f8e229d7a94abc9096da3118256"}, {name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(0), // should change the hash - expectedSignatureHash: "c2c7e77516a15f0f47f886b14cc47af2045eea15f176a9a560a9d47d8866958f"}, + expectedSignatureHash: "394192ce7faee4f5055939c6fa3bf41a3008ec29e667d60bd5203987850debd4"}, {name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, + expectedSignatureHash: "354c6ac137e5a3d05e85e9740039909202c20f8e229d7a94abc9096da3118256"}, {name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash - expectedSignatureHash: "2034eec2acc08c49d3896cc1bda214904ca850fc5989518885465b5a3154ee7f"}, + expectedSignatureHash: "55b1a9f7ee395ea37a8a6da804c9a654216364a42e37d329c5dc69c349369825"}, {name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash - expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, + expectedSignatureHash: "354c6ac137e5a3d05e85e9740039909202c20f8e229d7a94abc9096da3118256"}, {name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2, - expectedSignatureHash: "84ae3bb03202efc587d97e5aea7b80581b82242b969e6dea13b8daa32d24c0c1"}, + expectedSignatureHash: "8f386eefc0b389615279025f9c537102047fdf079df9a17ddad39d726130c736"}, {name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2, modificationFunction: modifyOutput(1), // shouldn't change the hash - expectedSignatureHash: "84ae3bb03202efc587d97e5aea7b80581b82242b969e6dea13b8daa32d24c0c1"}, + expectedSignatureHash: "8f386eefc0b389615279025f9c537102047fdf079df9a17ddad39d726130c736"}, {name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0, - expectedSignatureHash: "b2ccf259a65c3231d741a03420967b95563c3928cc15d3d15e8e795f383ab48b"}, + expectedSignatureHash: "7062156c393e71c6308f9d451a9f4850d9c331f77372d165bb9bcf0296e6a3d3"}, {name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2, - expectedSignatureHash: "652c8cd0ac050e41aad347ea09ee788360eec70908ba22fe5bba5bdde49b8ae1"}, + expectedSignatureHash: "84b56500814e4c7de8569ef6a5dfc269ca35db3160adaebedd92e68fe9d2c02b"}, // subnetwork transaction {name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0, - expectedSignatureHash: "2e828c04f5f03e4ce4b3de1fa5303400da5fa504291b760f5f6d4e98fc24597f"}, + expectedSignatureHash: "ab783013148f1fbc6a0c29c5e2e320ea1dab61122f4b556810ef07c96871964a"}, {name: "subnetwork-all-modify-payload", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyPayload, // should change the hash - expectedSignatureHash: "d5f3993aa8b7f47df52f78f2be9965f928c9cca9ac9e9542f1190b9d5ed6c17d"}, + expectedSignatureHash: "bad87ce0a6d5fade1bb9eb5de572a3a9904e6d0ef5d627b97c69380818c1ad6f"}, {name: "subnetwork-all-modify-gas", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyGas, // should change the hash - expectedSignatureHash: "e74d4a9fa5cdf476299ebdfa03f3c8021a157f814731ea11f6a6d606dc5cd439"}, + expectedSignatureHash: "54bdd33d4c8ea1baac6e92a129ad8a6bb90803b7b21387cc4ec9640752f4bb61"}, {name: "subnetwork-all-subnetwork-id", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifySubnetworkID, // should change the hash - expectedSignatureHash: "ca8bf9bc42cda2ec3ce8bee090011072e56ff4d0d8616d5c20cefe5f84d7fb37"}, + expectedSignatureHash: "e71d0226c6c0cc26e0a99146f597ff9b9b51406f64854235b18f741d4c87eac4"}, } for _, test := range tests { diff --git a/domain/consensus/utils/estimatedsize/transaction_estimated_size.go b/domain/consensus/utils/estimatedsize/transaction_estimated_size.go deleted file mode 100644 index 55d8c4320..000000000 --- a/domain/consensus/utils/estimatedsize/transaction_estimated_size.go +++ /dev/null @@ -1,65 +0,0 @@ -package estimatedsize - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" -) - -// TransactionEstimatedSerializedSize is the estimated size of a transaction in some -// serialization. This has to be deterministic, but not necessarily accurate, since -// it's only used as the size component in the transaction mass and block size limit -// calculation. -func TransactionEstimatedSerializedSize(tx *externalapi.DomainTransaction) uint64 { - if transactionhelper.IsCoinBase(tx) { - return 0 - } - size := uint64(0) - size += 2 // Txn Version - size += 8 // number of inputs (uint64) - for _, input := range tx.Inputs { - size += transactionInputEstimatedSerializedSize(input) - } - - size += 8 // number of outputs (uint64) - for _, output := range tx.Outputs { - size += TransactionOutputEstimatedSerializedSize(output) - } - - size += 8 // lock time (uint64) - size += externalapi.DomainSubnetworkIDSize - size += 8 // gas (uint64) - size += externalapi.DomainHashSize // payload hash - - size += 8 // length of the payload (uint64) - size += uint64(len(tx.Payload)) - - return size -} - -func transactionInputEstimatedSerializedSize(input *externalapi.DomainTransactionInput) uint64 { - size := uint64(0) - size += outpointEstimatedSerializedSize() - - size += 8 // length of signature script (uint64) - size += uint64(len(input.SignatureScript)) - - size += 8 // sequence (uint64) - return size -} - -func outpointEstimatedSerializedSize() uint64 { - size := uint64(0) - size += externalapi.DomainHashSize // ID - size += 4 // index (uint32) - return size -} - -// TransactionOutputEstimatedSerializedSize is the same as TransactionEstimatedSerializedSize but for outputs only -func TransactionOutputEstimatedSerializedSize(output *externalapi.DomainTransactionOutput) uint64 { - size := uint64(0) - size += 8 // value (uint64) - size += 2 //output.ScriptPublicKey.Version (uint 16) - size += 8 // length of script public key (uint64) - size += uint64(len(output.ScriptPublicKey.Script)) - return size -} diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index 459cdbd5a..3a51bc795 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -242,13 +242,9 @@ func getSigOpCount(pops []parsedOpcode, precise bool) int { nSigs := 0 for i, pop := range pops { switch pop.opcode.value { - case OpCheckSig: - fallthrough - case OpCheckSigVerify: + case OpCheckSig, OpCheckSigVerify, OpCheckSigECDSA: nSigs++ - case OpCheckMultiSig: - fallthrough - case OpCheckMultiSigVerify: + case OpCheckMultiSig, OpCheckMultiSigVerify, OpCheckMultiSigECDSA: // If we are being precise then look for familiar // patterns for multisig, for now all we recognize is // OP_1 - OP_16 to signify the number of pubkeys. diff --git a/domain/dagconfig/consensus_defaults.go b/domain/dagconfig/consensus_defaults.go index 4688ed1be..a4f3bac80 100644 --- a/domain/dagconfig/consensus_defaults.go +++ b/domain/dagconfig/consensus_defaults.go @@ -1,8 +1,9 @@ package dagconfig import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "time" + + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" ) // The documentation refers to the following constants which aren't explicated in the code: @@ -23,30 +24,32 @@ import ( const ( defaultMaxCoinbasePayloadLength = 150 - // defaultMaxBlockSize is a bound on the size of a block in bytes, larger values increase the bound d + // defaultMaxBlockMass is a bound on the mass of a block, larger values increase the bound d // on the round trip time of a block, which affects the other parameters as described below - defaultMaxBlockSize = 50_000 - // defaultMaxBlockParents is the number of blocks any block can point to. - // Should be about d/defaultTargetTimePerBlock where d is a bound on the round trip time of a block. - defaultMaxBlockParents = 10 + defaultMaxBlockMass = 500_000 + // defaultMassPerTxByte, defaultMassPerScriptPubKeyByte and defaultMassPerSigOp define the number of grams per + // transaction byte, script pub key byte and sig op respectively. + // These values are used when calculating a transactions mass. defaultMassPerTxByte = 1 defaultMassPerScriptPubKeyByte = 10 - defaultMassPerSigOp = 10000 - // defaultMergeSetSizeLimit is a bound on the size of the past of a block and the size of the past - // of its selected parent. Any block which violates this bound is invalid. - // Should be at least an order of magnitude smaller than defaultFinalityDuration/defaultTargetTimePerBlock. - // (Higher values make pruning attacks easier by a constant, lower values make merging after a split or a spike - // in block take longer) - defaultMergeSetSizeLimit = 1000 - defaultMaxMassAcceptedByBlock = 500_000 - defaultBaseSubsidy = 50 * constants.SompiPerKaspa - defaultCoinbasePayloadScriptPublicKeyMaxLength = 150 + defaultMassPerSigOp = 1000 + // defaultMaxBlockParents is the number of blocks any block can point to. + // Should be about d/defaultTargetTimePerBlock where d is a bound on the round trip time of a block. + defaultMaxBlockParents = 10 // defaultGHOSTDAGK is a bound on the number of blue blocks in the anticone of a blue block. Approximates the maximal // width of the network. // Formula (1) in section 4.2 of the PHATOM paper shows how to calculate defaultGHOSTDAGK. The delta term represents a bound // on the expected fraction of the network life in which the width was higher than defaultGHOSTDAGK. The current value of K // was calculated for d = 5 seconds and delta = 0.05. defaultGHOSTDAGK = 18 + // defaultMergeSetSizeLimit is a bound on the size of the past of a block and the size of the past + // of its selected parent. Any block which violates this bound is invalid. + // Should be at least an order of magnitude smaller than defaultFinalityDuration/defaultTargetTimePerBlock. + // (Higher values make pruning attacks easier by a constant, lower values make merging after a split or a spike + // in block take longer) + defaultMergeSetSizeLimit = defaultGHOSTDAGK * 10 + defaultBaseSubsidy = 50 * constants.SompiPerKaspa + defaultCoinbasePayloadScriptPublicKeyMaxLength = 150 // defaultDifficultyAdjustmentWindowSize is the number of blocks in a block's past used to calculate its difficulty // target. defaultDifficultyAdjustmentWindowSize = 2640 diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 96d886f75..cae374d7c 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -150,8 +150,8 @@ type Params struct { // MaxCoinbasePayloadLength is the maximum length in bytes allowed for a block's coinbase's payload MaxCoinbasePayloadLength uint64 - // MaxBlockSize is the maximum size in bytes a block is allowed - MaxBlockSize uint64 + // MaxBlockMass is the maximum mass a block is allowed + MaxBlockMass uint64 // MaxBlockParents is the maximum number of blocks a block is allowed to point to MaxBlockParents model.KType @@ -171,9 +171,6 @@ type Params struct { // MergeSetSizeLimit is the maximum number of blocks in a block's merge set MergeSetSizeLimit uint64 - // MaxMassAcceptedByBlock is the maximum total transaction mass a block may accept. - MaxMassAcceptedByBlock uint64 - // CoinbasePayloadScriptPublicKeyMaxLength is the maximum allowed script public key in the coinbase's payload CoinbasePayloadScriptPublicKeyMaxLength uint8 @@ -242,13 +239,12 @@ var MainnetParams = Params{ DisableDifficultyAdjustment: false, MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, - MaxBlockSize: defaultMaxBlockSize, + MaxBlockMass: defaultMaxBlockMass, MaxBlockParents: defaultMaxBlockParents, MassPerTxByte: defaultMassPerTxByte, MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, MassPerSigOp: defaultMassPerSigOp, MergeSetSizeLimit: defaultMergeSetSizeLimit, - MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, BaseSubsidy: defaultBaseSubsidy, CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } @@ -299,13 +295,12 @@ var TestnetParams = Params{ DisableDifficultyAdjustment: false, MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, - MaxBlockSize: defaultMaxBlockSize, + MaxBlockMass: defaultMaxBlockMass, MaxBlockParents: defaultMaxBlockParents, MassPerTxByte: defaultMassPerTxByte, MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, MassPerSigOp: defaultMassPerSigOp, MergeSetSizeLimit: defaultMergeSetSizeLimit, - MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, BaseSubsidy: defaultBaseSubsidy, CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } @@ -360,13 +355,12 @@ var SimnetParams = Params{ DisableDifficultyAdjustment: true, MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, - MaxBlockSize: defaultMaxBlockSize, + MaxBlockMass: defaultMaxBlockMass, MaxBlockParents: defaultMaxBlockParents, MassPerTxByte: defaultMassPerTxByte, MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, MassPerSigOp: defaultMassPerSigOp, MergeSetSizeLimit: defaultMergeSetSizeLimit, - MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, BaseSubsidy: defaultBaseSubsidy, CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } @@ -417,13 +411,12 @@ var DevnetParams = Params{ DisableDifficultyAdjustment: false, MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, - MaxBlockSize: defaultMaxBlockSize, + MaxBlockMass: defaultMaxBlockMass, MaxBlockParents: defaultMaxBlockParents, MassPerTxByte: defaultMassPerTxByte, MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, MassPerSigOp: defaultMassPerSigOp, MergeSetSizeLimit: defaultMergeSetSizeLimit, - MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, BaseSubsidy: defaultBaseSubsidy, CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } diff --git a/domain/miningmanager/factory.go b/domain/miningmanager/factory.go index 204d5be6a..b23648681 100644 --- a/domain/miningmanager/factory.go +++ b/domain/miningmanager/factory.go @@ -19,7 +19,7 @@ func (f *factory) NewMiningManager(consensus externalapi.Consensus, params *dagc mempoolConfig *mempoolpkg.Config) MiningManager { mempool := mempoolpkg.New(mempoolConfig, consensus) - blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, params.MaxMassAcceptedByBlock) + blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, params.MaxBlockMass) return &miningManager{ mempool: mempool, diff --git a/domain/miningmanager/mempool/check_transaction_standard.go b/domain/miningmanager/mempool/check_transaction_standard.go index 9026be701..870053fbd 100644 --- a/domain/miningmanager/mempool/check_transaction_standard.go +++ b/domain/miningmanager/mempool/check_transaction_standard.go @@ -3,11 +3,12 @@ package mempool import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/processes/transactionvalidator" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/util" ) @@ -36,10 +37,9 @@ const ( // (1 + 15*74 + 3) + (15*34 + 3) + 23 = 1650 maximumStandardSignatureScriptSize = 1650 - // maximumStandardTransactionSize is the maximum size allowed for transactions that - // are considered standard and will therefore be relayed and considered - // for mining. - maximumStandardTransactionSize = 100000 + // maximumStandardTransactionMass is the maximum mass allowed for transactions that + // are considered standard and will therefore be relayed and considered for mining. + maximumStandardTransactionMass = 100000 ) func (mp *mempool) checkTransactionStandardInIsolation(transaction *externalapi.DomainTransaction) error { @@ -59,10 +59,9 @@ func (mp *mempool) checkTransactionStandardInIsolation(transaction *externalapi. // almost as much to process as the sender fees, limit the maximum // size of a transaction. This also helps mitigate CPU exhaustion // attacks. - serializedLength := estimatedsize.TransactionEstimatedSerializedSize(transaction) - if serializedLength > maximumStandardTransactionSize { - str := fmt.Sprintf("transaction size of %d is larger than max allowed size of %d", - serializedLength, maximumStandardTransactionSize) + if transaction.Mass > maximumStandardTransactionMass { + str := fmt.Sprintf("transaction mass of %d is larger than max allowed size of %d", + transaction.Mass, maximumStandardTransactionMass) return transactionRuleError(RejectNonstandard, str) } @@ -129,7 +128,7 @@ func (mp *mempool) IsTransactionOutputDust(output *externalapi.DomainTransaction // The most common scripts are pay-to-pubkey, and as per the above // breakdown, the minimum size of a p2pk input script is 148 bytes. So // that figure is used. - totalSerializedSize := estimatedsize.TransactionOutputEstimatedSerializedSize(output) + 148 + totalSerializedSize := transactionvalidator.TransactionOutputEstimatedSerializedSize(output) + 148 // The output is considered dust if the cost to the network to spend the // coins is more than 1/3 of the minimum free transaction relay fee. @@ -176,8 +175,7 @@ func (mp *mempool) checkTransactionStandardInContext(transaction *externalapi.Do } } - serializedSize := estimatedsize.TransactionEstimatedSerializedSize(transaction) - minimumFee := mp.minimumRequiredTransactionRelayFee(serializedSize) + minimumFee := mp.minimumRequiredTransactionRelayFee(transaction.Mass) if transaction.Fee < minimumFee { str := fmt.Sprintf("transaction %s has %d fees which is under the required amount of %d", consensushashing.TransactionID(transaction), transaction.Fee, minimumFee) @@ -188,14 +186,12 @@ func (mp *mempool) checkTransactionStandardInContext(transaction *externalapi.Do } // minimumRequiredTransactionRelayFee returns the minimum transaction fee required for a -// transaction with the passed serialized size to be accepted into the memory -// pool and relayed. -func (mp *mempool) minimumRequiredTransactionRelayFee(serializedSize uint64) uint64 { +// transaction with the passed mass to be accepted into the mampool and relayed. +func (mp *mempool) minimumRequiredTransactionRelayFee(mass uint64) uint64 { // Calculate the minimum fee for a transaction to be allowed into the // mempool and relayed by scaling the base fee. MinimumRelayTransactionFee is in - // sompi/kB so multiply by serializedSize (which is in bytes) and - // divide by 1000 to get minimum sompis. - minimumFee := (serializedSize * uint64(mp.config.MinimumRelayTransactionFee)) / 1000 + // sompi/kg so multiply by mass (which is in grams) and divide by 1000 to get minimum sompis. + minimumFee := (mass * uint64(mp.config.MinimumRelayTransactionFee)) / 1000 if minimumFee == 0 && mp.config.MinimumRelayTransactionFee > 0 { minimumFee = uint64(mp.config.MinimumRelayTransactionFee) diff --git a/domain/miningmanager/mempool/check_transaction_standard_test.go b/domain/miningmanager/mempool/check_transaction_standard_test.go index 64e959056..faa5145b5 100644 --- a/domain/miningmanager/mempool/check_transaction_standard_test.go +++ b/domain/miningmanager/mempool/check_transaction_standard_test.go @@ -44,13 +44,13 @@ func TestCalcMinRequiredTxRelayFee(t *testing.T) { }, { "max standard tx size with default minimum relay fee", - maximumStandardTransactionSize, + maximumStandardTransactionMass, defaultMinimumRelayTransactionFee, 100000, }, { "max standard tx size with max sompi relay fee", - maximumStandardTransactionSize, + maximumStandardTransactionMass, util.MaxSompi, util.MaxSompi, }, @@ -244,7 +244,7 @@ func TestCheckTransactionStandardInIsolation(t *testing.T) { name: "Transaction size is too large", tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{{ Value: 0, - ScriptPublicKey: &externalapi.ScriptPublicKey{bytes.Repeat([]byte{0x00}, maximumStandardTransactionSize+1), 0}, + ScriptPublicKey: &externalapi.ScriptPublicKey{bytes.Repeat([]byte{0x00}, maximumStandardTransactionMass+1), 0}, }}}, height: 300000, isStandard: false, diff --git a/domain/miningmanager/mempool/config.go b/domain/miningmanager/mempool/config.go index fa4121dfb..1905e4962 100644 --- a/domain/miningmanager/mempool/config.go +++ b/domain/miningmanager/mempool/config.go @@ -18,11 +18,13 @@ const ( defaultOrphanExpireIntervalSeconds uint64 = 60 defaultOrphanExpireScanIntervalSeconds uint64 = 10 - defaultMaximumOrphanTransactionSize = 100000 + defaultMaximumOrphanTransactionMass = 100000 // defaultMaximumOrphanTransactionCount should remain small as long as we have recursion in // removeOrphans when removeRedeemers = true defaultMaximumOrphanTransactionCount = 50 + // defaultMinimumRelayTransactionFee specifies the minimum transaction fee for a transaction to be accepted to + // the mempool and relayed. It is specified in sompi per 1kg (or 1000 grams) of transaction mass. defaultMinimumRelayTransactionFee = util.Amount(1000) // Standard transaction version range might be different from what consensus accepts, therefore @@ -41,10 +43,10 @@ type Config struct { TransactionExpireScanIntervalSeconds uint64 OrphanExpireIntervalDAAScore uint64 OrphanExpireScanIntervalDAAScore uint64 - MaximumOrphanTransactionSize uint64 + MaximumOrphanTransactionMass uint64 MaximumOrphanTransactionCount uint64 AcceptNonStandard bool - MaximumMassAcceptedByBlock uint64 + MaximumMassPerBlock uint64 MinimumRelayTransactionFee util.Amount MinimumStandardTransactionVersion uint16 MaximumStandardTransactionVersion uint16 @@ -61,10 +63,10 @@ func DefaultConfig(dagParams *dagconfig.Params) *Config { TransactionExpireScanIntervalSeconds: defaultTransactionExpireScanIntervalSeconds, OrphanExpireIntervalDAAScore: defaultOrphanExpireIntervalSeconds / targetBlocksPerSecond, OrphanExpireScanIntervalDAAScore: defaultOrphanExpireScanIntervalSeconds / targetBlocksPerSecond, - MaximumOrphanTransactionSize: defaultMaximumOrphanTransactionSize, + MaximumOrphanTransactionMass: defaultMaximumOrphanTransactionMass, MaximumOrphanTransactionCount: defaultMaximumOrphanTransactionCount, AcceptNonStandard: dagParams.RelayNonStdTxs, - MaximumMassAcceptedByBlock: dagParams.MaxMassAcceptedByBlock, + MaximumMassPerBlock: dagParams.MaxBlockMass, MinimumRelayTransactionFee: defaultMinimumRelayTransactionFee, MinimumStandardTransactionVersion: defaultMinimumStandardTransactionVersion, MaximumStandardTransactionVersion: defaultMaximumStandardTransactionVersion, diff --git a/domain/miningmanager/mempool/orphan_pool.go b/domain/miningmanager/mempool/orphan_pool.go index a89c28310..de9cc8209 100644 --- a/domain/miningmanager/mempool/orphan_pool.go +++ b/domain/miningmanager/mempool/orphan_pool.go @@ -10,7 +10,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" "github.com/pkg/errors" ) @@ -44,7 +43,7 @@ func (op *orphansPool) maybeAddOrphan(transaction *externalapi.DomainTransaction return err } - err = op.checkOrphanSize(transaction) + err = op.checkOrphanMass(transaction) if err != nil { return err } @@ -87,12 +86,11 @@ func (op *orphansPool) limitOrphanPoolSize() error { return nil } -func (op *orphansPool) checkOrphanSize(transaction *externalapi.DomainTransaction) error { - serializedLength := estimatedsize.TransactionEstimatedSerializedSize(transaction) - if serializedLength > op.mempool.config.MaximumOrphanTransactionSize { +func (op *orphansPool) checkOrphanMass(transaction *externalapi.DomainTransaction) error { + if transaction.Mass > op.mempool.config.MaximumOrphanTransactionMass { str := fmt.Sprintf("orphan transaction size of %d bytes is "+ "larger than max allowed size of %d bytes", - serializedLength, op.mempool.config.MaximumOrphanTransactionSize) + transaction.Mass, op.mempool.config.MaximumOrphanTransactionMass) return transactionRuleError(RejectBadOrphan, str) } return nil diff --git a/domain/miningmanager/mempool/validate_and_insert_transaction.go b/domain/miningmanager/mempool/validate_and_insert_transaction.go index e8d559e22..fdd481670 100644 --- a/domain/miningmanager/mempool/validate_and_insert_transaction.go +++ b/domain/miningmanager/mempool/validate_and_insert_transaction.go @@ -16,6 +16,9 @@ func (mp *mempool) validateAndInsertTransaction(transaction *externalapi.DomainT fmt.Sprintf("validateAndInsertTransaction %s", consensushashing.TransactionID(transaction))) defer onEnd() + // Populate mass in the beginning, it will be used in multiple places throughout the validation and insertion. + mp.consensus.PopulateMass(transaction) + err = mp.validateTransactionPreUTXOEntry(transaction) if err != nil { return nil, err diff --git a/domain/miningmanager/mempool/validate_transaction.go b/domain/miningmanager/mempool/validate_transaction.go index a4910d1ff..42e77c9e2 100644 --- a/domain/miningmanager/mempool/validate_transaction.go +++ b/domain/miningmanager/mempool/validate_transaction.go @@ -44,13 +44,6 @@ func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.Domai } func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error { - transactionID := consensushashing.TransactionID(transaction) - if transaction.Mass > mp.config.MaximumMassAcceptedByBlock { - return transactionRuleError(RejectInvalid, fmt.Sprintf("transaction %s mass is %d which is "+ - "higher than the maxmimum of %d", transactionID, - transaction.Mass, mp.config.MaximumMassAcceptedByBlock)) - } - if !mp.config.AcceptNonStandard { err := mp.checkTransactionStandardInContext(transaction) if err != nil { diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index 8e8cb576b..b59e2a2d1 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -28,8 +28,7 @@ type overrideDAGParamsConfig struct { K *model.KType `json:"k"` MaxBlockParents *model.KType `json:"maxBlockParents"` MergeSetSizeLimit *uint64 `json:"mergeSetSizeLimit"` - MaxMassAcceptedByBlock *uint64 `json:"maxMassAcceptedByBlock"` - MaxBlockSize *uint64 `json:"maxBlockSize"` + MaxBlockMass *uint64 `json:"maxBlockMass"` MaxCoinbasePayloadLength *uint64 `json:"maxCoinbasePayloadLength"` MassPerTxByte *uint64 `json:"massPerTxByte"` MassPerScriptPubKeyByte *uint64 `json:"massPerScriptPubKeyByte"` @@ -132,12 +131,8 @@ func (networkFlags *NetworkFlags) overrideDAGParams() error { networkFlags.ActiveNetParams.MergeSetSizeLimit = *config.MergeSetSizeLimit } - if config.MaxMassAcceptedByBlock != nil { - networkFlags.ActiveNetParams.MaxMassAcceptedByBlock = *config.MaxMassAcceptedByBlock - } - - if config.MaxBlockSize != nil { - networkFlags.ActiveNetParams.MaxBlockSize = *config.MaxBlockSize + if config.MaxBlockMass != nil { + networkFlags.ActiveNetParams.MaxBlockMass = *config.MaxBlockMass } if config.MaxCoinbasePayloadLength != nil { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 5acf82208..caf58ebde 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1,12 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.25.0 // protoc v3.12.3 // source: messages.proto package protowire import ( + proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -20,6 +21,10 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + type KaspadMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go index 09653ed68..102e61cfd 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go @@ -11,8 +11,7 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +const _ = grpc.SupportPackageIsVersion6 // P2PClient is the client API for P2P service. // @@ -30,7 +29,7 @@ func NewP2PClient(cc grpc.ClientConnInterface) P2PClient { } func (c *p2PClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (P2P_MessageStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &P2P_ServiceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...) + stream, err := c.cc.NewStream(ctx, &_P2P_serviceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...) if err != nil { return nil, err } @@ -72,20 +71,13 @@ type P2PServer interface { type UnimplementedP2PServer struct { } -func (UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { +func (*UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} +func (*UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} -// UnsafeP2PServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to P2PServer will -// result in compilation errors. -type UnsafeP2PServer interface { - mustEmbedUnimplementedP2PServer() -} - -func RegisterP2PServer(s grpc.ServiceRegistrar, srv P2PServer) { - s.RegisterService(&P2P_ServiceDesc, srv) +func RegisterP2PServer(s *grpc.Server, srv P2PServer) { + s.RegisterService(&_P2P_serviceDesc, srv) } func _P2P_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error { @@ -114,10 +106,7 @@ func (x *p2PMessageStreamServer) Recv() (*KaspadMessage, error) { return m, nil } -// P2P_ServiceDesc is the grpc.ServiceDesc for P2P service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var P2P_ServiceDesc = grpc.ServiceDesc{ +var _P2P_serviceDesc = grpc.ServiceDesc{ ServiceName: "protowire.P2P", HandlerType: (*P2PServer)(nil), Methods: []grpc.MethodDesc{}, @@ -148,7 +137,7 @@ func NewRPCClient(cc grpc.ClientConnInterface) RPCClient { } func (c *rPCClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (RPC_MessageStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &RPC_ServiceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...) + stream, err := c.cc.NewStream(ctx, &_RPC_serviceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...) if err != nil { return nil, err } @@ -190,20 +179,13 @@ type RPCServer interface { type UnimplementedRPCServer struct { } -func (UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { +func (*UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} +func (*UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} -// UnsafeRPCServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to RPCServer will -// result in compilation errors. -type UnsafeRPCServer interface { - mustEmbedUnimplementedRPCServer() -} - -func RegisterRPCServer(s grpc.ServiceRegistrar, srv RPCServer) { - s.RegisterService(&RPC_ServiceDesc, srv) +func RegisterRPCServer(s *grpc.Server, srv RPCServer) { + s.RegisterService(&_RPC_serviceDesc, srv) } func _RPC_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error { @@ -232,10 +214,7 @@ func (x *rPCMessageStreamServer) Recv() (*KaspadMessage, error) { return m, nil } -// RPC_ServiceDesc is the grpc.ServiceDesc for RPC service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var RPC_ServiceDesc = grpc.ServiceDesc{ +var _RPC_serviceDesc = grpc.ServiceDesc{ ServiceName: "protowire.RPC", HandlerType: (*RPCServer)(nil), Methods: []grpc.MethodDesc{}, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go index 449a1c050..5628e1481 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -1,12 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.25.0 // protoc v3.12.3 // source: p2p.proto package protowire import ( + proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -20,6 +21,10 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + type RequestAddressesMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -335,6 +340,7 @@ type TransactionInput struct { PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + SigOpCount uint32 `protobuf:"varint,4,opt,name=sigOpCount,proto3" json:"sigOpCount,omitempty"` } func (x *TransactionInput) Reset() { @@ -390,6 +396,13 @@ func (x *TransactionInput) GetSequence() uint64 { return 0 } +func (x *TransactionInput) GetSigOpCount() uint32 { + if x != nil { + return x.SigOpCount + } + return 0 +} + type Outpoint struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2269,7 +2282,7 @@ var file_p2p_proto_rawDesc = []byte{ 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, + 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb9, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, @@ -2279,7 +2292,9 @@ var file_p2p_proto_rawDesc = []byte{ 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, + 0x4f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto index cff1b740a..428d96f47 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto @@ -36,6 +36,7 @@ message TransactionInput{ Outpoint previousOutpoint = 1; bytes signatureScript = 2; uint64 sequence = 3; + uint32 sigOpCount = 4; } message Outpoint{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index 89b100926..712578532 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -1,9 +1,10 @@ package protowire import ( + "math" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/pkg/errors" - "math" ) func (x *KaspadMessage_Transaction) toAppMessage() (appmessage.Message, error) { @@ -64,11 +65,14 @@ func (x *TransactionInput) toAppMessage() (*appmessage.TxIn, error) { if x == nil { return nil, errors.Wrapf(errorNil, "TransactionInput is nil") } + if x.SigOpCount > math.MaxUint8 { + return nil, errors.New("TransactionInput SigOpCount > math.MaxUint8") + } outpoint, err := x.PreviousOutpoint.toAppMessage() if err != nil { return nil, err } - return appmessage.NewTxIn(outpoint, x.SignatureScript, x.Sequence), nil + return appmessage.NewTxIn(outpoint, x.SignatureScript, x.Sequence, byte(x.SigOpCount)), nil } func (x *TransactionOutput) toAppMessage() (*appmessage.TxOut, error) { @@ -95,6 +99,7 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { }, SignatureScript: input.SignatureScript, Sequence: input.Sequence, + SigOpCount: uint32(input.SigOpCount), } } @@ -118,5 +123,4 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { Gas: msgTx.Gas, Payload: msgTx.Payload, } - } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index 5bf129276..e4608773e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -230,6 +230,7 @@ Receivers of any ResponseMessage are expected to check whether its error field i | previousOutpoint | [RpcOutpoint](#protowire.RpcOutpoint) | | | | signatureScript | [string](#string) | | | | sequence | [uint64](#uint64) | | | +| sigOpCount | [uint32](#uint32) | | | | verboseData | [RpcTransactionInputVerboseData](#protowire.RpcTransactionInputVerboseData) | | | @@ -727,6 +728,7 @@ SubmitTransactionRequestMessage submits a transaction to the mempool | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | transaction | [RpcTransaction](#protowire.RpcTransaction) | | | +| allowOrphan | [bool](#bool) | | | diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 9cee7f263..db4209441 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -10,13 +10,14 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.25.0 // protoc v3.12.3 // source: rpc.proto package protowire import ( + proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -30,6 +31,10 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + type SubmitBlockResponseMessage_RejectReason int32 const ( @@ -501,6 +506,7 @@ type RpcTransactionInput struct { PreviousOutpoint *RpcOutpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` SignatureScript string `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + SigOpCount uint32 `protobuf:"varint,5,opt,name=sigOpCount,proto3" json:"sigOpCount,omitempty"` VerboseData *RpcTransactionInputVerboseData `protobuf:"bytes,4,opt,name=verboseData,proto3" json:"verboseData,omitempty"` } @@ -557,6 +563,13 @@ func (x *RpcTransactionInput) GetSequence() uint64 { return 0 } +func (x *RpcTransactionInput) GetSigOpCount() uint32 { + if x != nil { + return x.SigOpCount + } + return 0 +} + func (x *RpcTransactionInput) GetVerboseData() *RpcTransactionInputVerboseData { if x != nil { return x.VerboseData @@ -815,7 +828,7 @@ type RpcTransactionVerboseData struct { TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` - Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + Mass uint64 `protobuf:"varint,4,opt,name=mass,proto3" json:"mass,omitempty"` BlockHash string `protobuf:"bytes,12,opt,name=blockHash,proto3" json:"blockHash,omitempty"` BlockTime uint64 `protobuf:"varint,14,opt,name=blockTime,proto3" json:"blockTime,omitempty"` } @@ -866,9 +879,9 @@ func (x *RpcTransactionVerboseData) GetHash() string { return "" } -func (x *RpcTransactionVerboseData) GetSize() uint64 { +func (x *RpcTransactionVerboseData) GetMass() uint64 { if x != nil { - return x.Size + return x.Mass } return 0 } @@ -5337,7 +5350,7 @@ var file_rpc_proto_rawDesc = []byte{ 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x0b, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xec, 0x01, 0x0a, + 0x0b, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8c, 0x02, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, @@ -5347,7 +5360,9 @@ var file_rpc_proto_rawDesc = []byte{ 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x4b, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x4f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, @@ -5392,8 +5407,8 @@ var file_rpc_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x73, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x6d, 0x61, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 97cd21d4f..8e9fb4ddd 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -61,6 +61,7 @@ message RpcTransactionInput { RpcOutpoint previousOutpoint = 1; string signatureScript = 2; uint64 sequence = 3; + uint32 sigOpCount = 5; RpcTransactionInputVerboseData verboseData = 4; } @@ -90,7 +91,7 @@ message RpcUtxoEntry { message RpcTransactionVerboseData{ string transactionId = 1; string hash = 2; - uint64 size = 3; + uint64 mass = 4; string blockHash = 12; uint64 blockTime = 14; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go index ffaf6f213..292eb02a7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go @@ -146,6 +146,9 @@ func (x *RpcTransactionInput) toAppMessage() (*appmessage.RPCTransactionInput, e if x == nil { return nil, errors.Wrapf(errorNil, "RpcTransactionInput is nil") } + if x.SigOpCount > math.MaxUint8 { + return nil, errors.New("TransactionInput SigOpCount > math.MaxUint8") + } outpoint, err := x.PreviousOutpoint.toAppMessage() if err != nil { return nil, err @@ -163,6 +166,7 @@ func (x *RpcTransactionInput) toAppMessage() (*appmessage.RPCTransactionInput, e SignatureScript: x.SignatureScript, Sequence: x.Sequence, VerboseData: verboseData, + SigOpCount: byte(x.SigOpCount), }, nil } @@ -179,6 +183,7 @@ func (x *RpcTransactionInput) fromAppMessage(message *appmessage.RPCTransactionI SignatureScript: message.SignatureScript, Sequence: message.Sequence, VerboseData: verboseData, + SigOpCount: uint32(message.SigOpCount), } } @@ -291,7 +296,7 @@ func (x *RpcTransactionVerboseData) toAppMessage() (*appmessage.RPCTransactionVe return &appmessage.RPCTransactionVerboseData{ TransactionID: x.TransactionId, Hash: x.Hash, - Size: x.Size, + Mass: x.Mass, BlockHash: x.BlockHash, BlockTime: x.BlockTime, }, nil @@ -301,7 +306,7 @@ func (x *RpcTransactionVerboseData) fromAppMessage(message *appmessage.RPCTransa *x = RpcTransactionVerboseData{ TransactionId: message.TransactionID, Hash: message.Hash, - Size: message.Size, + Mass: message.Mass, BlockHash: message.BlockHash, BlockTime: message.BlockTime, } diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 5b75af93e..b783c20d3 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -95,7 +95,7 @@ func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessa func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, payer, payee *appHarness) *appmessage.MsgTx { txIns := make([]*appmessage.TxIn, 1) - txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensushashing.TransactionID(firstBlockCoinbase), 0), []byte{}, 0) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensushashing.TransactionID(firstBlockCoinbase), 0), []byte{}, 0, 1) payeeAddress, err := util.DecodeAddress(payee.miningAddress, util.Bech32PrefixKaspaSim) if err != nil { diff --git a/testing/integration/utxo_index_test.go b/testing/integration/utxo_index_test.go index f6789cb17..1a313465e 100644 --- a/testing/integration/utxo_index_test.go +++ b/testing/integration/utxo_index_test.go @@ -161,7 +161,7 @@ func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAdd } txIns := make([]*appmessage.TxIn, 1) - txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{}, 0) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{}, 0, 1) payeeAddress, err := util.DecodeAddress(miningAddress1, util.Bech32PrefixKaspaSim) if err != nil {