// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package evm
import (
"fmt"
"math/big"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/utils/crypto"
safemath "github.com/ava-labs/avalanchego/utils/math"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
// UnsignedExportTx is an unsigned ExportTx
type UnsignedExportTx struct {
avax.Metadata
// true iff this transaction has already passed syntactic verification
syntacticallyVerified bool
// ID of the network on which this tx was issued
NetworkID uint32 `serialize:"true" json:"networkID"`
// ID of this blockchain.
BlockchainID ids.ID `serialize:"true" json:"blockchainID"`
// Which chain to send the funds to
DestinationChain ids.ID `serialize:"true" json:"destinationChain"`
// Inputs
Ins []EVMInput `serialize:"true" json:"inputs"`
// Outputs that are exported to the chain
ExportedOutputs []*avax.TransferableOutput `serialize:"true" json:"exportedOutputs"`
}
// InputUTXOs returns an empty set
func (tx *UnsignedExportTx) InputUTXOs() ids.Set { return ids.Set{} }
// Verify this transaction is well-formed
func (tx *UnsignedExportTx) Verify(
avmID ids.ID,
ctx *snow.Context,
feeAmount uint64,
feeAssetID ids.ID,
) error {
switch {
case tx == nil:
return errNilTx
case tx.syntacticallyVerified: // already passed syntactic verification
return nil
case tx.DestinationChain != avmID:
return errWrongChainID
case len(tx.ExportedOutputs) == 0:
return errNoExportOutputs
case tx.NetworkID != ctx.NetworkID:
return errWrongNetworkID
case ctx.ChainID != tx.BlockchainID:
return errWrongBlockchainID
}
for _, in := range tx.Ins {
if err := in.Verify(); err != nil {
return err
}
}
for _, out := range tx.ExportedOutputs {
if err := out.Verify(); err != nil {
return err
}
}
if !avax.IsSortedTransferableOutputs(tx.ExportedOutputs, Codec) {
return errOutputsNotSorted
}
tx.syntacticallyVerified = true
return nil
}
// SemanticVerify this transaction is valid.
func (tx *UnsignedExportTx) SemanticVerify(
vm *VM,
stx *Tx,
) TxError {
if err := tx.Verify(vm.ctx.XChainID, vm.ctx, vm.txFee, vm.ctx.AVAXAssetID); err != nil {
return permError{err}
}
if len(tx.Ins) != len(stx.Creds) {
return