Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions vms/saevm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ type SinceGenesis struct {
mempool *txpool.Mempool
pushGossiper *gossip.PushGossiper[*tx.Tx]

// TODO(StephenButtolph): Remove. This is only used by the tests.
warpVerifier *saewarp.Verifier
// TODO(alarso16): remove later
hooks *hook.Points

// onClose are executed in reverse order during [SinceGenesis.Shutdown].
// If a resource depends on another resource, it MUST be added AFTER the
Expand Down Expand Up @@ -186,6 +186,7 @@ func (vm *SinceGenesis) Initialize(
vm.db = avaDB
vm.mempool = txpool.New(txs, snowCtx, inner.GethRPCBackends())
vm.onClose = append(vm.onClose, vm.mempool.Close)
vm.hooks = hooks

metrics := prometheus.NewRegistry()
if err := snowCtx.Metrics.Register("coreth", metrics); err != nil {
Expand Down Expand Up @@ -240,10 +241,10 @@ func (vm *SinceGenesis) Initialize(
}

{ // ========== Warp Handler ==========
vm.warpVerifier = saewarp.NewVerifier(&blockClient{vm: inner}, warpStorage)
warpVerifier := saewarp.NewVerifier(&blockClient{vm: inner}, warpStorage)
warpHandler := acp118.NewCachedHandler(
lru.NewCache[ids.ID, []byte](warpSignatureCacheSize),
vm.warpVerifier,
warpVerifier,
snowCtx.WarpSigner,
)
if err := inner.AddHandler(p2p.SignatureRequestHandlerID, warpHandler); err != nil {
Expand Down
129 changes: 129 additions & 0 deletions vms/saevm/vm_atomic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright (C) 2019, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package saevm

import (
"math/big"
"testing"

"github.com/ava-labs/avalanchego/api"
"github.com/ava-labs/avalanchego/graft/coreth/core/extstate"
"github.com/ava-labs/avalanchego/graft/coreth/params"
"github.com/ava-labs/avalanchego/graft/coreth/plugin/evm/atomic"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/vms/saevm/tx"
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/common/hexutil"
"github.com/ava-labs/libevm/rpc"
"github.com/stretchr/testify/require"
)

// TestExportTx adds an atomic export and verifies that the exported UTXO is in shared memory.
func TestExportTx(t *testing.T) {
sut := newSUT(t)

tests := []struct {
name string
amount uint64
destChain ids.ID
}{
{
name: "P Chain",
amount: 1,
destChain: sut.snowCtx.SubnetID,
},
{
name: "X Chain",
amount: 1,
destChain: sut.snowCtx.XChainID,
},
{
name: "Random Chain",
amount: 1,
destChain: ids.GenerateTestID(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exportTx := sut.issueExportTx(t, tt.destChain, tt.amount)

// Tx added build time
b := sut.buildAndVerifyBlock(t, nil)
opts, err := sut.vm.hooks.EndOfBlockOps(b.EthBlock())
require.NoError(t, err)
require.Len(t, opts, 1)

// Result should be available after execution
sut.acceptAndExecuteBlock(t, b)
sm := sut.atomicMemory.NewSharedMemory(tt.destChain)
indexedValues, _, _, err := sm.Indexed(sut.snowCtx.ChainID, [][]byte{sut.atomicKey.Address().Bytes()}, nil, nil, 3)
require.NoError(t, err)
require.Len(t, indexedValues, 1)

// Exact UTXO should be in shared memory
id, err := exportTx.ID()
require.NoError(t, err)
_, req, err := exportTx.AtomicOps(id) // codec isn't exported, can still get UTXO marshaled like this
require.NoError(t, err)
require.Len(t, req.PutRequests, 1)
require.Equal(t, req.PutRequests[0].Value, indexedValues[0])

// Check nonce for address, it should be incremented by 1
prevBlock := new(big.Int).Sub(b.Number(), common.Big1)
startNonce, err := sut.client.NonceAt(sut.ctx, sut.atomicKey.EthAddress(), prevBlock)
require.NoError(t, err)
endNonce, err := sut.client.NonceAt(sut.ctx, sut.atomicKey.EthAddress(), b.Number())
require.NoError(t, err)
require.Equal(t, startNonce+1, endNonce)
})
}
}

func (s *SUT) issueExportTx(t *testing.T, chainID ids.ID, amount uint64) *tx.Tx {
id, err := s.vm.LastAccepted(s.ctx)
require.NoError(t, err)

b := s.vm.GethRPCBackends()
state, _, err := b.StateAndHeaderByNumberOrHash(
s.ctx, rpc.BlockNumberOrHashWithHash(common.Hash(id), true),
)

var hex hexutil.Big
require.NoError(t, s.client.Client().CallContext(s.ctx, &hex, "eth_baseFee"), "eth_baseFee")
baseFee := (*big.Int)(&hex)

rules := params.TestDurangoChainConfig.Rules(new(big.Int), params.IsMergeTODO, 0)

// TODO(alarso16): Use new atomic code. This is identical after marshaled.
corethTx, err := atomic.NewExportTx(
s.snowCtx,
*params.GetRulesExtra(rules),
extstate.New(state),
s.snowCtx.AVAXAssetID,
1,
chainID,
s.atomicKey.Address(),
baseFee,
[]*secp256k1.PrivateKey{s.atomicKey},
)
require.NoError(t, err)
txBytes := corethTx.SignedBytes()

res := &api.JSONTxID{}
txStr, err := formatting.Encode(formatting.Hex, txBytes)
require.NoError(t, err)
err = s.avaxClient.Call(res, "avax.issueTx", &api.FormattedTx{
Tx: txStr,
Encoding: formatting.Hex,
})
require.NoError(t, err)

// Copy into new Tx type for better testing.
newTx, err := tx.Parse(txBytes)
require.NoError(t, err)

return newTx
}
Loading
Loading