aboutsummaryrefslogtreecommitdiff
path: root/plugin/evm
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/evm')
-rw-r--r--plugin/evm/export_tx.go24
-rw-r--r--plugin/evm/import_tx.go23
-rw-r--r--plugin/evm/tx.go2
-rw-r--r--plugin/evm/vm.go9
4 files changed, 48 insertions, 10 deletions
diff --git a/plugin/evm/export_tx.go b/plugin/evm/export_tx.go
index 249b7cf..9af11e0 100644
--- a/plugin/evm/export_tx.go
+++ b/plugin/evm/export_tx.go
@@ -5,15 +5,17 @@ package evm
import (
"fmt"
+ "math/big"
+
+ "github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/snow"
"github.com/ava-labs/gecko/utils/crypto"
+ safemath "github.com/ava-labs/gecko/utils/math"
"github.com/ava-labs/gecko/vms/components/avax"
"github.com/ava-labs/gecko/vms/secp256k1fx"
-
- safemath "github.com/ava-labs/gecko/utils/math"
)
// UnsignedExportTx is an unsigned ExportTx
@@ -31,6 +33,8 @@ type UnsignedExportTx struct {
Ins []EVMInput `serialize:"true" json:"inputs"`
// Outputs that are exported to the chain
ExportedOutputs []*avax.TransferableOutput `serialize:"true" json:"exportedOutputs"`
+ // EVM nonce
+ nonce uint64
}
// InputUTXOs returns an empty set
@@ -144,3 +148,19 @@ func (vm *VM) newExportTx(
}
return tx, utx.Verify(vm.ctx.XChainID, vm.ctx, vm.txFee, vm.ctx.AVAXAssetID)
}
+
+func (tx *UnsignedExportTx) EVMStateTransfer(state *state.StateDB) error {
+ for _, from := range tx.Ins {
+ amount := new(big.Int).Mul(
+ new(big.Int).SetUint64(from.Amount), x2cRate)
+ if state.GetBalance(from.Address).Cmp(amount) < 0 {
+ return errInsufficientFunds
+ }
+ state.SubBalance(from.Address, amount)
+ if state.GetNonce(from.Address) != tx.nonce {
+ return errInvalidNonce
+ }
+ state.SetNonce(from.Address, tx.nonce+1)
+ }
+ return nil
+}
diff --git a/plugin/evm/import_tx.go b/plugin/evm/import_tx.go
index 995e488..68e5fed 100644
--- a/plugin/evm/import_tx.go
+++ b/plugin/evm/import_tx.go
@@ -34,8 +34,8 @@ type UnsignedImportTx struct {
ImportedInputs []*avax.TransferableInput `serialize:"true" json:"importedInputs"`
// Outputs
Outs []EVMOutput `serialize:"true" json:"outputs"`
- // Memo field contains arbitrary bytes, up to maxMemoSize
- Memo []byte `serialize:"true" json:"memo"`
+ // EVM nonce
+ nonce uint64
}
// InputUTXOs returns the UTXOIDs of the imported funds
@@ -193,6 +193,10 @@ func (vm *VM) newImportTx(
})
}
+ nonce, err := vm.GetAcceptedNonce(to)
+ if err != nil {
+ return nil, err
+ }
// Create the transaction
utx := &UnsignedImportTx{
NetworkID: vm.ctx.NetworkID,
@@ -200,6 +204,7 @@ func (vm *VM) newImportTx(
Outs: outs,
ImportedInputs: importedInputs,
SourceChain: chainID,
+ nonce: nonce,
}
tx := &Tx{UnsignedTx: utx}
if err := tx.Sign(vm.codec, signers); err != nil {
@@ -208,11 +213,15 @@ func (vm *VM) newImportTx(
return tx, utx.Verify(vm.ctx.XChainID, vm.ctx, vm.txFee, vm.ctx.AVAXAssetID)
}
-func (tx *UnsignedImportTx) EVMStateTransfer(state *state.StateDB) {
+func (tx *UnsignedImportTx) EVMStateTransfer(state *state.StateDB) error {
for _, to := range tx.Outs {
- amount := new(big.Int).SetUint64(to.Amount)
- state.AddBalance(to.Address, new(big.Int).Mul(amount, x2cRate))
- nonce := state.GetNonce(to.Address)
- state.SetNonce(to.Address, nonce+1)
+ state.AddBalance(to.Address,
+ new(big.Int).Mul(
+ new(big.Int).SetUint64(to.Amount), x2cRate))
+ if state.GetNonce(to.Address) != tx.nonce {
+ return errInvalidNonce
+ }
+ state.SetNonce(to.Address, tx.nonce+1)
}
+ return nil
}
diff --git a/plugin/evm/tx.go b/plugin/evm/tx.go
index dfd49f0..7e60c79 100644
--- a/plugin/evm/tx.go
+++ b/plugin/evm/tx.go
@@ -65,7 +65,7 @@ type UnsignedAtomicTx interface {
// Accept this transaction with the additionally provided state transitions.
Accept(ctx *snow.Context, batch database.Batch) error
- EVMStateTransfer(state *state.StateDB)
+ EVMStateTransfer(state *state.StateDB) error
}
// Tx is a signed transaction
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 53810ee..6155728 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -95,6 +95,7 @@ var (
errNoExportOutputs = errors.New("no export outputs")
errOutputsNotSorted = errors.New("outputs not sorted")
errOverflowExport = errors.New("overflow when computing export amount + txFee")
+ errInvalidNonce = errors.New("invalid nonce")
)
func maxDuration(x, y time.Duration) time.Duration {
@@ -721,3 +722,11 @@ func (vm *VM) GetSpendableCanonical(keys []*crypto.PrivateKeySECP256K1R, amount
}
return inputs, signers, nil
}
+
+func (vm *VM) GetAcceptedNonce(address common.Address) (uint64, error) {
+ state, err := vm.chain.BlockState(vm.lastAccepted.ethBlock)
+ if err != nil {
+ return 0, err
+ }
+ return state.GetNonce(address), nil
+}