// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package evm
import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"math/big"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/ava-labs/coreth"
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/eth"
"github.com/ava-labs/coreth/node"
"github.com/ava-labs/coreth/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
avalancheRPC "github.com/gorilla/rpc/v2"
"github.com/ava-labs/avalanchego/api/admin"
"github.com/ava-labs/avalanchego/cache"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/database/prefixdb"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/snow/choices"
"github.com/ava-labs/avalanchego/snow/consensus/snowman"
"github.com/ava-labs/avalanchego/utils/codec"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/timer"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ava-labs/avalanchego/utils/wrappers"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
commonEng "github.com/ava-labs/avalanchego/snow/engine/common"
avalancheJSON "github.com/ava-labs/avalanchego/utils/json"
)
var (
x2cRate = big.NewInt(1000000000)
)
const (
lastAcceptedKey = "snowman_lastAccepted"
acceptedPrefix = "snowman_accepted"
)
const (
minBlockTime = 250 * time.Millisecond
maxBlockTime = 1000 * time.Millisecond
batchSize = 250
maxUTXOsToFetch = 1024
blockCacheSize = 1 << 10 // 1024
codecVersion = uint16(0)
)
const (
bdTimerStateMin = iota
bdTimerStateMax
bdTimerStateLong
)
var (
txFee = units.MilliAvax
errEmptyBlock = errors.New("empty block")
errCreateBlock = errors.New("couldn't create block")
errUnknownBlock = errors.New("unknown block")
errBlockFrequency = errors.New("too frequent block issuance")
errUnsupportedFXs = errors.New("unsupported feature extensions")
errInvalidBlock = errors.New("invalid block")
errInvalidAddr = errors.New("invalid hex address")
errTooManyAtomicTx = errors.New("too many pending atomic txs")
errAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo")
errNoImportInputs = errors.New("tx has no imported inputs")
errInputsNotSortedUnique = errors.New("inputs not sorted and unique")
errPublicKeySignatureMismatch = errors.New("signature doesn't match public key")
errSignatureInputsMismatch = errors.New("number of inputs does not match number of signatures")
errWrongChainID = errors.New("tx has wrong chain ID")
errInsufficientFunds = errors.New("insufficient funds")
errNoExportOutputs = errors.New("tx has no export outputs")
errOutputsNotSorted = errors.New("tx 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 {
if x > y {
return x
}
return y
}
// Codec does serialization and deserialization
var Codec codec.Manager
func init() {
Codec = codec.NewDefaultManager()
c := codec.NewDefault()
errs := wrappers.Errs{}
errs.Add(
c.RegisterType(&UnsignedImportTx{}),
c.RegisterType(&UnsignedExportTx{}),
)
c.Skip(3)
errs.Add(
c.RegisterType(&secp256k1fx.TransferInput{}),
c.RegisterType(&secp256k1fx.MintOutput{}),
c.RegisterType(&secp256k1fx.TransferOutput{}),
c.RegisterType(&secp256k1fx.MintOperation{}),
c.RegisterType(&secp256k1fx.Credential{}),
c.RegisterType(&secp256k1fx.Input{}),
c.RegisterType(&secp256k1fx.OutputOwners{}),
Codec.RegisterCodec(codecVersion, c),
)
if errs.Errored() {
panic(errs.Err)
}
}
// VM implements the snowman.ChainVM interface
type VM struct {
ctx *snow.Context
CLIConfig CommandLineConfig
chainID *big.Int
networkID uint64
genesisHash common.Hash
chain *coreth.ETHChain
chaindb Database
newBlockChan chan *Block
networkChan chan<- commonEng.Message
newMinedBlockSub *event.TypeMuxSubscription
acceptedDB database.Database
txPoolStabilizedLock sync.Mutex
txPoolStabilizedHead common.Hash
txPoolStabilizedOk chan struct{}
metalock sync.Mutex
blockCache, blockStatusCache cache.LRU
lastAccepted *Block
writingMetadata uint32
bdlock sync.Mutex
blockDelayTimer *timer.Timer
bdTimerState int8
bdGenWaitFlag bool
bdGenFlag bool
genlock sync.Mutex
txSubmitChan <-chan struct{}
atomicTxSubmitChan chan struct{}
baseCodec codec.