diff --git a/plugin/evm/atomic/tx_semantic_verifier.go b/plugin/evm/atomic/tx_semantic_verifier.go index 2acd4ad93f..8bb47df753 100644 --- a/plugin/evm/atomic/tx_semantic_verifier.go +++ b/plugin/evm/atomic/tx_semantic_verifier.go @@ -21,7 +21,7 @@ import ( "github.com/ava-labs/coreth/plugin/evm/upgrade/ap0" ) -var _ Visitor = (*SemanticVerifier)(nil) +var _ Visitor = (*semanticVerifier)(nil) var ( ErrAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo") @@ -44,20 +44,30 @@ type VerifierBackend struct { SecpCache *secp256k1.RecoverCache } -// SemanticVerifier is a visitor that checks the semantic validity of atomic transactions. -type SemanticVerifier struct { - Backend *VerifierBackend - Tx *Tx - Parent AtomicBlockContext - BaseFee *big.Int +// SemanticVerify checks the semantic validity of atomic transactions. +func (b *VerifierBackend) SemanticVerify(tx *Tx, parent AtomicBlockContext, baseFee *big.Int) error { + return tx.UnsignedAtomicTx.Visit(&semanticVerifier{ + backend: b, + tx: tx, + parent: parent, + baseFee: baseFee, + }) } -// ImportTx verifies this transaction is valid. -func (s *SemanticVerifier) ImportTx(utx *UnsignedImportTx) error { - backend := s.Backend +// semanticVerifier is a visitor that checks the semantic validity of atomic +// transactions. +type semanticVerifier struct { + backend *VerifierBackend + tx *Tx + parent AtomicBlockContext + baseFee *big.Int +} + +func (s *semanticVerifier) ImportTx(utx *UnsignedImportTx) error { + backend := s.backend ctx := backend.Ctx rules := backend.Rules - stx := s.Tx + stx := s.tx if err := utx.Verify(ctx, rules); err != nil { return err } @@ -71,7 +81,7 @@ func (s *SemanticVerifier) ImportTx(utx *UnsignedImportTx) error { if err != nil { return err } - txFee, err := CalculateDynamicFee(gasUsed, s.BaseFee) + txFee, err := CalculateDynamicFee(gasUsed, s.baseFee) if err != nil { return err } @@ -133,7 +143,7 @@ func (s *SemanticVerifier) ImportTx(utx *UnsignedImportTx) error { } } - return conflicts(backend, utx.InputUTXOs(), s.Parent) + return conflicts(backend, utx.InputUTXOs(), s.parent) } // conflicts returns an error if [inputs] conflicts with any of the atomic inputs contained in [ancestor] @@ -176,12 +186,11 @@ func conflicts(backend *VerifierBackend, inputs set.Set[ids.ID], ancestor Atomic return nil } -// ExportTx verifies this transaction is valid. -func (s *SemanticVerifier) ExportTx(utx *UnsignedExportTx) error { - backend := s.Backend +func (s *semanticVerifier) ExportTx(utx *UnsignedExportTx) error { + backend := s.backend ctx := backend.Ctx rules := backend.Rules - stx := s.Tx + stx := s.tx if err := utx.Verify(ctx, rules); err != nil { return err } @@ -195,7 +204,7 @@ func (s *SemanticVerifier) ExportTx(utx *UnsignedExportTx) error { if err != nil { return err } - txFee, err := CalculateDynamicFee(gasUsed, s.BaseFee) + txFee, err := CalculateDynamicFee(gasUsed, s.baseFee) if err != nil { return err } @@ -231,7 +240,7 @@ func (s *SemanticVerifier) ExportTx(utx *UnsignedExportTx) error { if len(cred.Sigs) != 1 { return fmt.Errorf("expected one signature for EVM Input Credential, but found: %d", len(cred.Sigs)) } - pubKey, err := s.Backend.SecpCache.RecoverPublicKey(utx.Bytes(), cred.Sigs[0][:]) + pubKey, err := s.backend.SecpCache.RecoverPublicKey(utx.Bytes(), cred.Sigs[0][:]) if err != nil { return err } diff --git a/plugin/evm/export_tx_test.go b/plugin/evm/export_tx_test.go index d0a3aed252..06ee0d482e 100644 --- a/plugin/evm/export_tx_test.go +++ b/plugin/evm/export_tx_test.go @@ -932,15 +932,7 @@ func TestExportTxSemanticVerify(t *testing.T) { } t.Run(test.name, func(t *testing.T) { - tx := test.tx - exportTx := tx.UnsignedAtomicTx - - err := exportTx.Visit(&atomic.SemanticVerifier{ - Backend: backend, - Tx: tx, - Parent: parent, - BaseFee: test.baseFee, - }) + err := backend.SemanticVerify(test.tx, parent, test.baseFee) if test.shouldErr && err == nil { t.Fatalf("should have errored but returned valid") } @@ -1781,8 +1773,6 @@ func TestNewExportTx(t *testing.T) { t.Fatal(err) } - exportTx := tx.UnsignedAtomicTx - backend := &atomic.VerifierBackend{ Ctx: tvm.vm.ctx, Fx: &tvm.vm.fx, @@ -1791,16 +1781,11 @@ func TestNewExportTx(t *testing.T) { BlockFetcher: tvm.vm, SecpCache: tvm.vm.secpCache, } - - if err := exportTx.Visit(&atomic.SemanticVerifier{ - Backend: backend, - Tx: tx, - Parent: parent, - BaseFee: parent.ethBlock.BaseFee(), - }); err != nil { + if err := backend.SemanticVerify(tx, parent, parent.ethBlock.BaseFee()); err != nil { t.Fatal("newExportTx created an invalid transaction", err) } + exportTx := tx.UnsignedAtomicTx burnedAVAX, err := exportTx.Burned(tvm.vm.ctx.AVAXAssetID) if err != nil { t.Fatal(err) @@ -1986,7 +1971,6 @@ func TestNewExportTxMulticoin(t *testing.T) { t.Fatal(err) } - exportTx := tx.UnsignedAtomicTx backend := &atomic.VerifierBackend{ Ctx: tvm.vm.ctx, Fx: &tvm.vm.fx, @@ -1995,13 +1979,7 @@ func TestNewExportTxMulticoin(t *testing.T) { BlockFetcher: tvm.vm, SecpCache: tvm.vm.secpCache, } - - if err := exportTx.Visit(&atomic.SemanticVerifier{ - Backend: backend, - Tx: tx, - Parent: parent, - BaseFee: parent.ethBlock.BaseFee(), - }); err != nil { + if err := backend.SemanticVerify(tx, parent, parent.ethBlock.BaseFee()); err != nil { t.Fatal("newExportTx created an invalid transaction", err) } @@ -2009,7 +1987,9 @@ func TestNewExportTxMulticoin(t *testing.T) { if err != nil { t.Fatalf("Failed to create commit batch for VM due to %s", err) } - chainID, atomicRequests, err := exportTx.AtomicOps() + + exportTx := tx.UnsignedAtomicTx + chainID, atomicRequests, err := tx.UnsignedAtomicTx.AtomicOps() if err != nil { t.Fatalf("Failed to accept export transaction due to: %s", err) } diff --git a/plugin/evm/tx_test.go b/plugin/evm/tx_test.go index 6017f69205..ea96466c89 100644 --- a/plugin/evm/tx_test.go +++ b/plugin/evm/tx_test.go @@ -122,12 +122,7 @@ func executeTxTest(t *testing.T, test atomicTxTest) { BlockFetcher: tvm.vm, SecpCache: tvm.vm.secpCache, } - if err := tx.UnsignedAtomicTx.Visit(&atomic.SemanticVerifier{ - Backend: backend, - Tx: tx, - Parent: lastAcceptedBlock, - BaseFee: baseFee, - }); len(test.semanticVerifyErr) == 0 && err != nil { + if err := backend.SemanticVerify(tx, lastAcceptedBlock, baseFee); len(test.semanticVerifyErr) == 0 && err != nil { t.Fatalf("SemanticVerify failed unexpectedly due to: %s", err) } else if len(test.semanticVerifyErr) != 0 { if err == nil { diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index d1bdd21996..3973eea1e6 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -1602,12 +1602,7 @@ func (vm *VM) verifyTx(tx *atomic.Tx, parentHash common.Hash, baseFee *big.Int, BlockFetcher: vm, SecpCache: vm.secpCache, } - if err := tx.UnsignedAtomicTx.Visit(&atomic.SemanticVerifier{ - Backend: atomicBackend, - Tx: tx, - Parent: parent, - BaseFee: baseFee, - }); err != nil { + if atomicBackend.SemanticVerify(tx, parent, baseFee); err != nil { return err } return tx.UnsignedAtomicTx.EVMStateTransfer(vm.ctx, state) @@ -1646,17 +1641,11 @@ func (vm *VM) verifyTxs(txs []*atomic.Tx, parentHash common.Hash, baseFee *big.I BlockFetcher: vm, SecpCache: vm.secpCache, } - for _, atomicTx := range txs { - utx := atomicTx.UnsignedAtomicTx - if err := utx.Visit(&atomic.SemanticVerifier{ - Backend: atomicBackend, - Tx: atomicTx, - Parent: ancestor, - BaseFee: baseFee, - }); err != nil { - return fmt.Errorf("invalid block due to failed semanatic verify: %w at height %d", err, height) + for _, tx := range txs { + if atomicBackend.SemanticVerify(tx, ancestor, baseFee); err != nil { + return fmt.Errorf("invalid block due to failed semantic verify: %w at height %d", err, height) } - txInputs := utx.InputUTXOs() + txInputs := tx.UnsignedAtomicTx.InputUTXOs() if inputs.Overlaps(txInputs) { return atomic.ErrConflictingAtomicInputs }