Repository: kaspanet/kaspad
Pull request #1159 (2020-11-29 08:02:23)

[NOD-1551] Add SigCache to TransactionValidator + Option to manipulate it in TestConsensus


Patch:
diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go
index 17907cac..4e95ca67 100644
--- a/domain/consensus/factory.go
+++ b/domain/consensus/factory.go
@@ -338,11 +338,14 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD
 
 	testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager)
 
+	testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator)
+
 	tstConsensus := &testConsensus{
 		consensus:                 consensusAsImplementation,
 		testConsensusStateManager: testConsensusStateManager,
 		testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation.
 			reachabilityManager),
+		testTransactionValidator: testTransactionValidator,
 	}
 	tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus)
 	teardown = func() {
diff --git a/domain/consensus/model/interface_processes_blockvalidator.go b/domain/consensus/model/interface_processes_blockvalidator.go
index 5a89c09c..0cdc771e 100644
--- a/domain/consensus/model/interface_processes_blockvalidator.go
+++ b/domain/consensus/model/interface_processes_blockvalidator.go
@@ -1,6 +1,8 @@
 package model
 
-import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+import (
+	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+)
 
 // BlockValidator exposes a set of validation classes, after which
 // it's possible to determine whether a block is valid
diff --git a/domain/consensus/model/interface_processes_transactionvalidator.go b/domain/consensus/model/interface_processes_transactionvalidator.go
index 2d8b09a8..ccf5de81 100644
--- a/domain/consensus/model/interface_processes_transactionvalidator.go
+++ b/domain/consensus/model/interface_processes_transactionvalidator.go
@@ -1,11 +1,21 @@
 package model
 
-import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+import (
+	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
+)
 
 // TransactionValidator exposes a set of validation classes, after which
 // it's possible to determine whether a transaction is valid
 type TransactionValidator interface {
 	ValidateTransactionInIsolation(transaction *externalapi.DomainTransaction) error
 	ValidateTransactionInContextAndPopulateMassAndFee(tx *externalapi.DomainTransaction,
-		povBlockHash *externalapi.DomainHash, selectedParentMedianTime int64) error
+		povTransactionHash *externalapi.DomainHash, selectedParentMedianTime int64) error
+}
+
+// TestTransactionValidator adds to the main TransactionValidator methods required by tests
+type TestTransactionValidator interface {
+	TransactionValidator
+	SigCache() *txscript.SigCache
+	SetSigCache(sigCache *txscript.SigCache)
 }
diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go
index edf88692..bc8dd7af 100644
--- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go
+++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go
@@ -189,7 +189,7 @@ func (v *transactionValidator) validateTransactionScripts(tx *externalapi.Domain
 
 		scriptPubKey := utxoEntry.ScriptPublicKey
 		vm, err := txscript.NewEngine(scriptPubKey, tx,
-			i, txscript.ScriptNoFlags, nil)
+			i, txscript.ScriptNoFlags, v.sigCache)
 		if err != nil {
 			return errors.Wrapf(ruleerrors.ErrScriptMalformed, "failed to parse input "+
 				"%d which references output %s - "+
diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator.go b/domain/consensus/processes/transactionvalidator/transactionvalidator.go
index 41c338b9..9500bb55 100644
--- a/domain/consensus/processes/transactionvalidator/transactionvalidator.go
+++ b/domain/consensus/processes/transactionvalidator/transactionvalidator.go
@@ -2,8 +2,11 @@ package transactionvalidator
 
 import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
 )
 
+const sigCacheSize = 10_000
+
 // transactionValidator exposes a set of validation classes, after which
 // it's possible to determine whether either a transaction is valid
 type transactionValidator struct {
@@ -12,6 +15,7 @@ type transactionValidator struct {
 	pastMedianTimeManager      model.PastMedianTimeManager
 	ghostdagDataStore          model.GHOSTDAGDataStore
 	enableNonNativeSubnetworks bool
+	sigCache                   *txscript.SigCache
 }
 
 // New instantiates a new TransactionValidator
@@ -26,5 +30,6 @@ func New(blockCoinbaseMaturity uint64,
 		databaseContext:            databaseContext,
 		pastMedianTimeManager:      pastMedianTimeManager,
 		ghostdagDataStore:          ghostdagDataStore,
+		sigCache:                   txscript.NewSigCache(sigCacheSize),
 	}
 }
diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go
index f87bb87b..6c83230f 100644
--- a/domain/consensus/utils/txscript/opcode.go
+++ b/domain/consensus/utils/txscript/opcode.go
@@ -2249,7 +2249,6 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
 		secpHash := secp256k1.Hash(*sigHash)
 		var valid bool
 		if vm.sigCache != nil {
-
 			valid = vm.sigCache.Exists(secpHash, parsedSig, parsedPubKey)
 			if !valid && parsedPubKey.SchnorrVerify(&secpHash, parsedSig) {
 				vm.sigCache.Add(secpHash, parsedSig, parsedPubKey)


Test patch:
diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go
index f87cb9f3..d1cdc657 100644
--- a/domain/consensus/model/testapi/test_consensus.go
+++ b/domain/consensus/model/testapi/test_consensus.go
@@ -48,5 +48,5 @@ type TestConsensus interface {
 	PruningManager() model.PruningManager
 	ReachabilityManager() model.TestReachabilityManager
 	SyncManager() model.SyncManager
-	TransactionValidator() model.TransactionValidator
+	TransactionValidator() model.TestTransactionValidator
 }
diff --git a/domain/consensus/processes/transactionvalidator/test_transaction_validator.go b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go
new file mode 100644
index 00000000..342b682e
--- /dev/null
+++ b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go
@@ -0,0 +1,23 @@
+package transactionvalidator
+
+import (
+	"github.com/kaspanet/kaspad/domain/consensus/model"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
+)
+
+type testTransactionValidator struct {
+	*transactionValidator
+}
+
+// NewTestTransactionValidator creates an instance of a TestTransactionValidator
+func NewTestTransactionValidator(baseTransactionValidator model.TransactionValidator) model.TestTransactionValidator {
+	return &testTransactionValidator{transactionValidator: baseTransactionValidator.(*transactionValidator)}
+}
+
+func (tbv *testTransactionValidator) SigCache() *txscript.SigCache {
+	return tbv.sigCache
+}
+
+func (tbv *testTransactionValidator) SetSigCache(sigCache *txscript.SigCache) {
+	tbv.sigCache = sigCache
+}
diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go
index d845b4e6..a0dc8393 100644
--- a/domain/consensus/test_consensus.go
+++ b/domain/consensus/test_consensus.go
@@ -12,9 +12,12 @@ type testConsensus struct {
 	testBlockBuilder          model.TestBlockBuilder
 	testReachabilityManager   model.TestReachabilityManager
 	testConsensusStateManager model.TestConsensusStateManager
+	testTransactionValidator  model.TestTransactionValidator
 }
 
-func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) {
+func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash,
+	coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (
+	*externalapi.DomainBlock, *model.UTXODiff, error) {
 
 	// Require write lock because BuildBlockWithParents stages temporary data
 	tc.lock.Lock()
diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go
index 0ab7f6cc..9d9061f3 100644
--- a/domain/consensus/test_consensus_getters.go
+++ b/domain/consensus/test_consensus_getters.go
@@ -116,6 +116,6 @@ func (tc *testConsensus) SyncManager() model.SyncManager {
 	return tc.syncManager
 }
 
-func (tc *testConsensus) TransactionValidator() model.TransactionValidator {
-	return tc.transactionValidator
+func (tc *testConsensus) TransactionValidator() model.TestTransactionValidator {
+	return tc.testTransactionValidator
 }