From d235e2c6a5788ec4a6cff15a16f56b38a3876a0d Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 28 Jun 2020 14:47:41 -0400 Subject: ... --- core/vm/analysis.go | 62 ++ core/vm/common.go | 99 +++ core/vm/contract.go | 184 ++++++ core/vm/contracts.go | 497 +++++++++++++++ core/vm/doc.go | 24 + core/vm/eips.go | 92 +++ core/vm/errors.go | 31 + core/vm/evm.go | 557 +++++++++++++++++ core/vm/gas.go | 53 ++ core/vm/gas_table.go | 441 ++++++++++++++ core/vm/gen_structlog.go | 111 ++++ core/vm/instructions.go | 1011 ++++++++++++++++++++++++++++++ core/vm/int_pool_verifier.go | 31 + core/vm/int_pool_verifier_empty.go | 23 + core/vm/interface.go | 87 +++ core/vm/interpreter.go | 300 +++++++++ core/vm/intpool.go | 106 ++++ core/vm/jump_table.go | 1183 ++++++++++++++++++++++++++++++++++++ core/vm/logger.go | 256 ++++++++ core/vm/logger_json.go | 87 +++ core/vm/memory.go | 124 ++++ core/vm/memory_table.go | 113 ++++ core/vm/opcodes.go | 555 +++++++++++++++++ core/vm/stack.go | 95 +++ core/vm/stack_table.go | 42 ++ 25 files changed, 6164 insertions(+) create mode 100644 core/vm/analysis.go create mode 100644 core/vm/common.go create mode 100644 core/vm/contract.go create mode 100644 core/vm/contracts.go create mode 100644 core/vm/doc.go create mode 100644 core/vm/eips.go create mode 100644 core/vm/errors.go create mode 100644 core/vm/evm.go create mode 100644 core/vm/gas.go create mode 100644 core/vm/gas_table.go create mode 100644 core/vm/gen_structlog.go create mode 100644 core/vm/instructions.go create mode 100644 core/vm/int_pool_verifier.go create mode 100644 core/vm/int_pool_verifier_empty.go create mode 100644 core/vm/interface.go create mode 100644 core/vm/interpreter.go create mode 100644 core/vm/intpool.go create mode 100644 core/vm/jump_table.go create mode 100644 core/vm/logger.go create mode 100644 core/vm/logger_json.go create mode 100644 core/vm/memory.go create mode 100644 core/vm/memory_table.go create mode 100644 core/vm/opcodes.go create mode 100644 core/vm/stack.go create mode 100644 core/vm/stack_table.go (limited to 'core/vm') diff --git a/core/vm/analysis.go b/core/vm/analysis.go new file mode 100644 index 0000000..0ccf47b --- /dev/null +++ b/core/vm/analysis.go @@ -0,0 +1,62 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +// bitvec is a bit vector which maps bytes in a program. +// An unset bit means the byte is an opcode, a set bit means +// it's data (i.e. argument of PUSHxx). +type bitvec []byte + +func (bits *bitvec) set(pos uint64) { + (*bits)[pos/8] |= 0x80 >> (pos % 8) +} +func (bits *bitvec) set8(pos uint64) { + (*bits)[pos/8] |= 0xFF >> (pos % 8) + (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) +} + +// codeSegment checks if the position is in a code segment. +func (bits *bitvec) codeSegment(pos uint64) bool { + return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 +} + +// codeBitmap collects data locations in code. +func codeBitmap(code []byte) bitvec { + // The bitmap is 4 bytes longer than necessary, in case the code + // ends with a PUSH32, the algorithm will push zeroes onto the + // bitvector outside the bounds of the actual code. + bits := make(bitvec, len(code)/8+1+4) + for pc := uint64(0); pc < uint64(len(code)); { + op := OpCode(code[pc]) + + if op >= PUSH1 && op <= PUSH32 { + numbits := op - PUSH1 + 1 + pc++ + for ; numbits >= 8; numbits -= 8 { + bits.set8(pc) // 8 + pc += 8 + } + for ; numbits > 0; numbits-- { + bits.set(pc) + pc++ + } + } else { + pc++ + } + } + return bits +} diff --git a/core/vm/common.go b/core/vm/common.go new file mode 100644 index 0000000..ead30fc --- /dev/null +++ b/core/vm/common.go @@ -0,0 +1,99 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "math/big" + + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" +) + +// calcMemSize64 calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +func calcMemSize64(off, l *big.Int) (uint64, bool) { + if !l.IsUint64() { + return 0, true + } + return calcMemSize64WithUint(off, l.Uint64()) +} + +// calcMemSize64WithUint calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +// Identical to calcMemSize64, but length is a uint64 +func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) { + // if length is zero, memsize is always zero, regardless of offset + if length64 == 0 { + return 0, false + } + // Check that offset doesn't overflow + if !off.IsUint64() { + return 0, true + } + offset64 := off.Uint64() + val := offset64 + length64 + // if value < either of it's parts, then it overflowed + return val, val < offset64 +} + +// getData returns a slice from the data based on the start and size and pads +// up to size with zero's. This function is overflow safe. +func getData(data []byte, start uint64, size uint64) []byte { + length := uint64(len(data)) + if start > length { + start = length + } + end := start + size + if end > length { + end = length + } + return common.RightPadBytes(data[start:end], int(size)) +} + +// getDataBig returns a slice from the data based on the start and size and pads +// up to size with zero's. This function is overflow safe. +func getDataBig(data []byte, start *big.Int, size *big.Int) []byte { + dlen := big.NewInt(int64(len(data))) + + s := math.BigMin(start, dlen) + e := math.BigMin(new(big.Int).Add(s, size), dlen) + return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64())) +} + +// bigUint64 returns the integer casted to a uint64 and returns whether it +// overflowed in the process. +func bigUint64(v *big.Int) (uint64, bool) { + return v.Uint64(), !v.IsUint64() +} + +// toWordSize returns the ceiled word size required for memory expansion. +func toWordSize(size uint64) uint64 { + if size > math.MaxUint64-31 { + return math.MaxUint64/32 + 1 + } + + return (size + 31) / 32 +} + +func allZero(b []byte) bool { + for _, byte := range b { + if byte != 0 { + return false + } + } + return true +} diff --git a/core/vm/contract.go b/core/vm/contract.go new file mode 100644 index 0000000..ed17402 --- /dev/null +++ b/core/vm/contract.go @@ -0,0 +1,184 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "math/big" + + "github.com/ava-labs/go-ethereum/common" +) + +// ContractRef is a reference to the contract's backing object +type ContractRef interface { + Address() common.Address +} + +// AccountRef implements ContractRef. +// +// Account references are used during EVM initialisation and +// it's primary use is to fetch addresses. Removing this object +// proves difficult because of the cached jump destinations which +// are fetched from the parent contract (i.e. the caller), which +// is a ContractRef. +type AccountRef common.Address + +// Address casts AccountRef to a Address +func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } + +// Contract represents an ethereum contract in the state database. It contains +// the contract code, calling arguments. Contract implements ContractRef +type Contract struct { + // CallerAddress is the result of the caller which initialised this + // contract. However when the "call method" is delegated this value + // needs to be initialised to that of the caller's caller. + CallerAddress common.Address + caller ContractRef + self ContractRef + + jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. + analysis bitvec // Locally cached result of JUMPDEST analysis + + Code []byte + CodeHash common.Hash + CodeAddr *common.Address + Input []byte + + Gas uint64 + value *big.Int +} + +// NewContract returns a new contract environment for the execution of EVM. +func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { + c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} + + if parent, ok := caller.(*Contract); ok { + // Reuse JUMPDEST analysis from parent context if available. + c.jumpdests = parent.jumpdests + } else { + c.jumpdests = make(map[common.Hash]bitvec) + } + + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas + // ensures a value is set + c.value = value + + return c +} + +func (c *Contract) validJumpdest(dest *big.Int) bool { + udest := dest.Uint64() + // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. + // Don't bother checking for JUMPDEST in that case. + if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) { + return false + } + // Only JUMPDESTs allowed for destinations + if OpCode(c.Code[udest]) != JUMPDEST { + return false + } + // Do we have a contract hash already? + if c.CodeHash != (common.Hash{}) { + // Does parent context have the analysis? + analysis, exist := c.jumpdests[c.CodeHash] + if !exist { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.jumpdests[c.CodeHash] = analysis + } + return analysis.codeSegment(udest) + } + // We don't have the code hash, most likely a piece of initcode not already + // in state trie. In that case, we do an analysis, and save it locally, so + // we don't have to recalculate it for every JUMP instruction in the execution + // However, we don't save it within the parent context + if c.analysis == nil { + c.analysis = codeBitmap(c.Code) + } + return c.analysis.codeSegment(udest) +} + +// AsDelegate sets the contract to be a delegate call and returns the current +// contract (for chaining calls) +func (c *Contract) AsDelegate() *Contract { + // NOTE: caller must, at all times be a contract. It should never happen + // that caller is something other than a Contract. + parent := c.caller.(*Contract) + c.CallerAddress = parent.CallerAddress + c.value = parent.value + + return c +} + +// GetOp returns the n'th element in the contract's byte array +func (c *Contract) GetOp(n uint64) OpCode { + return OpCode(c.GetByte(n)) +} + +// GetByte returns the n'th byte in the contract's byte array +func (c *Contract) GetByte(n uint64) byte { + if n < uint64(len(c.Code)) { + return c.Code[n] + } + + return 0 +} + +// Caller returns the caller of the contract. +// +// Caller will recursively call caller when the contract is a delegate +// call, including that of caller's caller. +func (c *Contract) Caller() common.Address { + return c.CallerAddress +} + +// UseGas attempts the use gas and subtracts it and returns true on success +func (c *Contract) UseGas(gas uint64) (ok bool) { + if c.Gas < gas { + return false + } + c.Gas -= gas + return true +} + +// Address returns the contracts address +func (c *Contract) Address() common.Address { + return c.self.Address() +} + +// Value returns the contract's value (sent to it from it's caller) +func (c *Contract) Value() *big.Int { + return c.value +} + +// SetCallCode sets the code of the contract and address of the backing data +// object +func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { + c.Code = code + c.CodeHash = hash + c.CodeAddr = addr +} + +// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. +// In case hash is not provided, the jumpdest analysis will not be saved to the parent context +func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { + c.Code = codeAndHash.code + c.CodeHash = codeAndHash.hash + c.CodeAddr = addr +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go new file mode 100644 index 0000000..54eab4e --- /dev/null +++ b/core/vm/contracts.go @@ -0,0 +1,497 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "crypto/sha256" + "encoding/binary" + "errors" + "math/big" + + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" + "github.com/ava-labs/go-ethereum/crypto" + "github.com/ava-labs/go-ethereum/crypto/blake2b" + "github.com/ava-labs/go-ethereum/crypto/bn256" + "golang.org/x/crypto/ripemd160" +) + +// PrecompiledContract is the basic interface for native Go contracts. The implementation +// requires a deterministic gas count based on the input size of the Run method of the +// contract. +type PrecompiledContract interface { + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(input []byte) ([]byte, error) // Run runs the precompiled contract +} + +// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum +// contracts used in the Frontier and Homestead releases. +var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, +} + +// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum +// contracts used in the Byzantium release. +var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModExp{}, + common.BytesToAddress([]byte{6}): &bn256AddByzantium{}, + common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{}, + common.BytesToAddress([]byte{8}): &bn256PairingByzantium{}, +} + +// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum +// contracts used in the Istanbul release. +var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModExp{}, + common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{9}): &blake2F{}, +} + +// RunPrecompiledContract runs and evaluates the output of a precompiled contract. +func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { + gas := p.RequiredGas(input) + if contract.UseGas(gas) { + return p.Run(input) + } + return nil, ErrOutOfGas +} + +// ECRECOVER implemented as a native contract. +type ecrecover struct{} + +func (c *ecrecover) RequiredGas(input []byte) uint64 { + return params.EcrecoverGas +} + +func (c *ecrecover) Run(input []byte) ([]byte, error) { + const ecRecoverInputLength = 128 + + input = common.RightPadBytes(input, ecRecoverInputLength) + // "input" is (hash, v, r, s), each 32 bytes + // but for ecrecover we want (r, s, v) + + r := new(big.Int).SetBytes(input[64:96]) + s := new(big.Int).SetBytes(input[96:128]) + v := input[63] - 27 + + // tighter sig s values input homestead only apply to tx sigs + if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + return nil, nil + } + // v needs to be at the end for libsecp256k1 + pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v)) + // make sure the public key is a valid one + if err != nil { + return nil, nil + } + + // the first byte of pubkey is bitcoin heritage + return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil +} + +// SHA256 implemented as a native contract. +type sha256hash struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *sha256hash) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas +} +func (c *sha256hash) Run(input []byte) ([]byte, error) { + h := sha256.Sum256(input) + return h[:], nil +} + +// RIPEMD160 implemented as a native contract. +type ripemd160hash struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *ripemd160hash) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas +} +func (c *ripemd160hash) Run(input []byte) ([]byte, error) { + ripemd := ripemd160.New() + ripemd.Write(input) + return common.LeftPadBytes(ripemd.Sum(nil), 32), nil +} + +// data copy implemented as a native contract. +type dataCopy struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *dataCopy) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas +} +func (c *dataCopy) Run(in []byte) ([]byte, error) { + return in, nil +} + +// bigModExp implements a native big integer exponential modular operation. +type bigModExp struct{} + +var ( + big1 = big.NewInt(1) + big4 = big.NewInt(4) + big8 = big.NewInt(8) + big16 = big.NewInt(16) + big32 = big.NewInt(32) + big64 = big.NewInt(64) + big96 = big.NewInt(96) + big480 = big.NewInt(480) + big1024 = big.NewInt(1024) + big3072 = big.NewInt(3072) + big199680 = big.NewInt(199680) +) + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bigModExp) RequiredGas(input []byte) uint64 { + var ( + baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) + expLen = new(big.Int).SetBytes(getData(input, 32, 32)) + modLen = new(big.Int).SetBytes(getData(input, 64, 32)) + ) + if len(input) > 96 { + input = input[96:] + } else { + input = input[:0] + } + // Retrieve the head 32 bytes of exp for the adjusted exponent length + var expHead *big.Int + if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 { + expHead = new(big.Int) + } else { + if expLen.Cmp(big32) > 0 { + expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32)) + } else { + expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64())) + } + } + // Calculate the adjusted exponent length + var msb int + if bitlen := expHead.BitLen(); bitlen > 0 { + msb = bitlen - 1 + } + adjExpLen := new(big.Int) + if expLen.Cmp(big32) > 0 { + adjExpLen.Sub(expLen, big32) + adjExpLen.Mul(big8, adjExpLen) + } + adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) + + // Calculate the gas cost of the operation + gas := new(big.Int).Set(math.BigMax(modLen, baseLen)) + switch { + case gas.Cmp(big64) <= 0: + gas.Mul(gas, gas) + case gas.Cmp(big1024) <= 0: + gas = new(big.Int).Add( + new(big.Int).Div(new(big.Int).Mul(gas, gas), big4), + new(big.Int).Sub(new(big.Int).Mul(big96, gas), big3072), + ) + default: + gas = new(big.Int).Add( + new(big.Int).Div(new(big.Int).Mul(gas, gas), big16), + new(big.Int).Sub(new(big.Int).Mul(big480, gas), big199680), + ) + } + gas.Mul(gas, math.BigMax(adjExpLen, big1)) + gas.Div(gas, new(big.Int).SetUint64(params.ModExpQuadCoeffDiv)) + + if gas.BitLen() > 64 { + return math.MaxUint64 + } + return gas.Uint64() +} + +func (c *bigModExp) Run(input []byte) ([]byte, error) { + var ( + baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() + expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() + modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() + ) + if len(input) > 96 { + input = input[96:] + } else { + input = input[:0] + } + // Handle a special case when both the base and mod length is zero + if baseLen == 0 && modLen == 0 { + return []byte{}, nil + } + // Retrieve the operands and execute the exponentiation + var ( + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + ) + if mod.BitLen() == 0 { + // Modulo 0 is undefined, return zero + return common.LeftPadBytes([]byte{}, int(modLen)), nil + } + return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil +} + +// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, +// returning it, or an error if the point is invalid. +func newCurvePoint(blob []byte) (*bn256.G1, error) { + p := new(bn256.G1) + if _, err := p.Unmarshal(blob); err != nil { + return nil, err + } + return p, nil +} + +// newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point, +// returning it, or an error if the point is invalid. +func newTwistPoint(blob []byte) (*bn256.G2, error) { + p := new(bn256.G2) + if _, err := p.Unmarshal(blob); err != nil { + return nil, err + } + return p, nil +} + +// runBn256Add implements the Bn256Add precompile, referenced by both +// Byzantium and Istanbul operations. +func runBn256Add(input []byte) ([]byte, error) { + x, err := newCurvePoint(getData(input, 0, 64)) + if err != nil { + return nil, err + } + y, err := newCurvePoint(getData(input, 64, 64)) + if err != nil { + return nil, err + } + res := new(bn256.G1) + res.Add(x, y) + return res.Marshal(), nil +} + +// bn256Add implements a native elliptic curve point addition conforming to +// Istanbul consensus rules. +type bn256AddIstanbul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { + return params.Bn256AddGasIstanbul +} + +func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) { + return runBn256Add(input) +} + +// bn256AddByzantium implements a native elliptic curve point addition +// conforming to Byzantium consensus rules. +type bn256AddByzantium struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { + return params.Bn256AddGasByzantium +} + +func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) { + return runBn256Add(input) +} + +// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by +// both Byzantium and Istanbul operations. +func runBn256ScalarMul(input []byte) ([]byte, error) { + p, err := newCurvePoint(getData(input, 0, 64)) + if err != nil { + return nil, err + } + res := new(bn256.G1) + res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) + return res.Marshal(), nil +} + +// bn256ScalarMulIstanbul implements a native elliptic curve scalar +// multiplication conforming to Istanbul consensus rules. +type bn256ScalarMulIstanbul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { + return params.Bn256ScalarMulGasIstanbul +} + +func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) { + return runBn256ScalarMul(input) +} + +// bn256ScalarMulByzantium implements a native elliptic curve scalar +// multiplication conforming to Byzantium consensus rules. +type bn256ScalarMulByzantium struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { + return params.Bn256ScalarMulGasByzantium +} + +func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) { + return runBn256ScalarMul(input) +} + +var ( + // true32Byte is returned if the bn256 pairing check succeeds. + true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + + // false32Byte is returned if the bn256 pairing check fails. + false32Byte = make([]byte, 32) + + // errBadPairingInput is returned if the bn256 pairing input is invalid. + errBadPairingInput = errors.New("bad elliptic curve pairing size") +) + +// runBn256Pairing implements the Bn256Pairing precompile, referenced by both +// Byzantium and Istanbul operations. +func runBn256Pairing(input []byte) ([]byte, error) { + // Handle some corner cases cheaply + if len(input)%192 > 0 { + return nil, errBadPairingInput + } + // Convert the input into a set of coordinates + var ( + cs []*bn256.G1 + ts []*bn256.G2 + ) + for i := 0; i < len(input); i += 192 { + c, err := newCurvePoint(input[i : i+64]) + if err != nil { + return nil, err + } + t, err := newTwistPoint(input[i+64 : i+192]) + if err != nil { + return nil, err + } + cs = append(cs, c) + ts = append(ts, t) + } + // Execute the pairing checks and return the results + if bn256.PairingCheck(cs, ts) { + return true32Byte, nil + } + return false32Byte, nil +} + +// bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve +// conforming to Istanbul consensus rules. +type bn256PairingIstanbul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { + return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul +} + +func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) { + return runBn256Pairing(input) +} + +// bn256PairingByzantium implements a pairing pre-compile for the bn256 curve +// conforming to Byzantium consensus rules. +type bn256PairingByzantium struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { + return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium +} + +func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) { + return runBn256Pairing(input) +} + +type blake2F struct{} + +func (c *blake2F) RequiredGas(input []byte) uint64 { + // If the input is malformed, we can't calculate the gas, return 0 and let the + // actual call choke and fault. + if len(input) != blake2FInputLength { + return 0 + } + return uint64(binary.BigEndian.Uint32(input[0:4])) +} + +const ( + blake2FInputLength = 213 + blake2FFinalBlockBytes = byte(1) + blake2FNonFinalBlockBytes = byte(0) +) + +var ( + errBlake2FInvalidInputLength = errors.New("invalid input length") + errBlake2FInvalidFinalFlag = errors.New("invalid final flag") +) + +func (c *blake2F) Run(input []byte) ([]byte, error) { + // Make sure the input is valid (correct lenth and final flag) + if len(input) != blake2FInputLength { + return nil, errBlake2FInvalidInputLength + } + if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes { + return nil, errBlake2FInvalidFinalFlag + } + // Parse the input into the Blake2b call parameters + var ( + rounds = binary.BigEndian.Uint32(input[0:4]) + final = (input[212] == blake2FFinalBlockBytes) + + h [8]uint64 + m [16]uint64 + t [2]uint64 + ) + for i := 0; i < 8; i++ { + offset := 4 + i*8 + h[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + } + for i := 0; i < 16; i++ { + offset := 68 + i*8 + m[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + } + t[0] = binary.LittleEndian.Uint64(input[196:204]) + t[1] = binary.LittleEndian.Uint64(input[204:212]) + + // Execute the compression function, extract and return the result + blake2b.F(&h, m, t, final, rounds) + + output := make([]byte, 64) + for i := 0; i < 8; i++ { + offset := i * 8 + binary.LittleEndian.PutUint64(output[offset:offset+8], h[i]) + } + return output, nil +} diff --git a/core/vm/doc.go b/core/vm/doc.go new file mode 100644 index 0000000..5864d0c --- /dev/null +++ b/core/vm/doc.go @@ -0,0 +1,24 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +/* +Package vm implements the Ethereum Virtual Machine. + +The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops +over a set of bytes and executes them according to the set of rules defined +in the Ethereum yellow paper. +*/ +package vm diff --git a/core/vm/eips.go b/core/vm/eips.go new file mode 100644 index 0000000..75e5fb1 --- /dev/null +++ b/core/vm/eips.go @@ -0,0 +1,92 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" + + "github.com/ava-labs/coreth/params" +) + +// EnableEIP enables the given EIP on the config. +// This operation writes in-place, and callers need to ensure that the globally +// defined jump tables are not polluted. +func EnableEIP(eipNum int, jt *JumpTable) error { + switch eipNum { + case 2200: + enable2200(jt) + case 1884: + enable1884(jt) + case 1344: + enable1344(jt) + default: + return fmt.Errorf("undefined eip %d", eipNum) + } + return nil +} + +// enable1884 applies EIP-1884 to the given jump table: +// - Increase cost of BALANCE to 700 +// - Increase cost of EXTCODEHASH to 700 +// - Increase cost of SLOAD to 800 +// - Define SELFBALANCE, with cost GasFastStep (5) +func enable1884(jt *JumpTable) { + // Gas cost changes + jt[BALANCE].constantGas = params.BalanceGasEIP1884 + jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884 + jt[SLOAD].constantGas = params.SloadGasEIP1884 + + // New opcode + jt[SELFBALANCE] = operation{ + execute: opSelfBalance, + constantGas: GasFastStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + } +} + +func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address())) + stack.push(balance) + return nil, nil +} + +// enable1344 applies EIP-1344 (ChainID Opcode) +// - Adds an opcode that returns the current chain’s EIP-155 unique identifier +func enable1344(jt *JumpTable) { + // New opcode + jt[CHAINID] = operation{ + execute: opChainID, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + } +} + +// opChainID implements CHAINID opcode +func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID) + stack.push(chainId) + return nil, nil +} + +// enable2200 applies EIP-2200 (Rebalance net-metered SSTORE) +func enable2200(jt *JumpTable) { + jt[SSTORE].dynamicGas = gasSStoreEIP2200 +} diff --git a/core/vm/errors.go b/core/vm/errors.go new file mode 100644 index 0000000..94f0ed8 --- /dev/null +++ b/core/vm/errors.go @@ -0,0 +1,31 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import "errors" + +// List execution errors +var ( + ErrOutOfGas = errors.New("out of gas") + ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") + ErrDepth = errors.New("max call depth exceeded") + ErrTraceLimitReached = errors.New("the number of logs reached the specified limit") + ErrInsufficientBalance = errors.New("insufficient balance for transfer") + ErrIncompatibleAccount = errors.New("incompatible account") + ErrContractAddressCollision = errors.New("contract address collision") + ErrNoCompatibleInterpreter = errors.New("no compatible interpreter") +) diff --git a/core/vm/evm.go b/core/vm/evm.go new file mode 100644 index 0000000..ff3587c --- /dev/null +++ b/core/vm/evm.go @@ -0,0 +1,557 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" + "math/big" + "sync/atomic" + "time" + + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/crypto" +) + +// emptyCodeHash is used by create to ensure deployment is disallowed to already +// deployed contract addresses (relevant after the account abstraction). +var emptyCodeHash = crypto.Keccak256Hash(nil) + +type ( + // CanTransferFunc is the signature of a transfer guard function + CanTransferFunc func(StateDB, common.Address, *big.Int) bool + CanTransferMCFunc func(StateDB, common.Address, common.Address, *common.Hash, *big.Int) int + // TransferFunc is the signature of a transfer function + TransferFunc func(StateDB, common.Address, common.Address, *big.Int) + TransferMCFunc func(StateDB, common.Address, common.Address, *common.Hash, *big.Int) + // GetHashFunc returns the n'th block hash in the blockchain + // and is used by the BLOCKHASH EVM op code. + GetHashFunc func(uint64) common.Hash +) + +// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. +func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { + if contract.CodeAddr != nil { + precompiles := PrecompiledContractsHomestead + if evm.chainRules.IsByzantium { + precompiles = PrecompiledContractsByzantium + } + if evm.chainRules.IsIstanbul { + precompiles = PrecompiledContractsIstanbul + } + if p := precompiles[*contract.CodeAddr]; p != nil { + return RunPrecompiledContract(p, input, contract) + } + } + for _, interpreter := range evm.interpreters { + if interpreter.CanRun(contract.Code) { + if evm.interpreter != interpreter { + // Ensure that the interpreter pointer is set back + // to its current value upon return. + defer func(i Interpreter) { + evm.interpreter = i + }(evm.interpreter) + evm.interpreter = interpreter + } + return interpreter.Run(contract, input, readOnly) + } + } + return nil, ErrNoCompatibleInterpreter +} + +// Context provides the EVM with auxiliary information. Once provided +// it shouldn't be modified. +type Context struct { + // CanTransfer returns whether the account contains + // sufficient ether to transfer the value + CanTransfer CanTransferFunc + CanTransferMC CanTransferMCFunc + // Transfer transfers ether from one account to the other + Transfer TransferFunc + TransferMultiCoin TransferMCFunc + // GetHash returns the hash corresponding to n + GetHash GetHashFunc + + // Message information + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE + + // Block information + Coinbase common.Address // Provides information for COINBASE + GasLimit uint64 // Provides information for GASLIMIT + BlockNumber *big.Int // Provides information for NUMBER + Time *big.Int // Provides information for TIME + Difficulty *big.Int // Provides information for DIFFICULTY +} + +// EVM is the Ethereum Virtual Machine base object and provides +// the necessary tools to run a contract on the given state with +// the provided context. It should be noted that any error +// generated through any of the calls should be considered a +// revert-state-and-consume-all-gas operation, no checks on +// specific errors should ever be performed. The interpreter makes +// sure that any errors generated are to be considered faulty code. +// +// The EVM should never be reused and is not thread safe. +type EVM struct { + // Context provides auxiliary blockchain related information + Context + // StateDB gives access to the underlying state + StateDB StateDB + // Depth is the current call stack + depth int + + // chainConfig contains information about the current chain + chainConfig *params.ChainConfig + // chain rules contains the chain rules for the current epoch + chainRules params.Rules + // virtual machine configuration options used to initialise the + // evm. + vmConfig Config + // global (to this context) ethereum virtual machine + // used throughout the execution of the tx. + interpreters []Interpreter + interpreter Interpreter + // abort is used to abort the EVM calling operations + // NOTE: must be set atomically + abort int32 + // callGasTemp holds the gas available for the current call. This is needed because the + // available gas is calculated in gasCall* according to the 63/64 rule and later + // applied in opCall*. + callGasTemp uint64 +} + +// NewEVM returns a new EVM. The returned EVM is not thread safe and should +// only ever be used *once*. +func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { + evm := &EVM{ + Context: ctx, + StateDB: statedb, + vmConfig: vmConfig, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(ctx.BlockNumber), + interpreters: make([]Interpreter, 0, 1), + } + + if chainConfig.IsEWASM(ctx.BlockNumber) { + // to be implemented by EVM-C and Wagon PRs. + // if vmConfig.EWASMInterpreter != "" { + // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":") + // path := extIntOpts[0] + // options := []string{} + // if len(extIntOpts) > 1 { + // options = extIntOpts[1..] + // } + // evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options)) + // } else { + // evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig)) + // } + panic("No supported ewasm interpreter yet.") + } + + // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here + // as we always want to have the built-in EVM as the failover option. + evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) + evm.interpreter = evm.interpreters[0] + + return evm +} + +// Cancel cancels any running EVM operation. This may be called concurrently and +// it's safe to be called multiple times. +func (evm *EVM) Cancel() { + atomic.StoreInt32(&evm.abort, 1) +} + +// Cancelled returns true if Cancel has been called +func (evm *EVM) Cancelled() bool { + return atomic.LoadInt32(&evm.abort) == 1 +} + +// Interpreter returns the current interpreter +func (evm *EVM) Interpreter() Interpreter { + return evm.interpreter +} + +// Call executes the contract associated with the addr with the given input as +// parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. +func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + // Fail if we're trying to transfer more than the available balance + if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + return nil, gas, ErrInsufficientBalance + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + if !evm.StateDB.Exist(addr) { + precompiles := PrecompiledContractsHomestead + if evm.chainRules.IsByzantium { + precompiles = PrecompiledContractsByzantium + } + if evm.chainRules.IsIstanbul { + precompiles = PrecompiledContractsIstanbul + } + if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 { + // Calling a non existing account, don't do anything, but ping the tracer + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + } + return nil, gas, nil + } + evm.StateDB.CreateAccount(addr) + } + evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, to, value, gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + // Even if the account has no code, we need to continue because it might be a precompile + start := time.Now() + + // Capture the tracer start/end events in debug mode + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + + defer func() { // Lazy evaluation of the parameters + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + }() + } + ret, err = run(evm, contract, input, false) + + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in homestead this also counts for code storage gas errors. + if err != nil { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + return ret, contract.Gas, err +} + +// This allows the user transfer balance of a specified coinId in addition to a normal Call(). +func (evm *EVM) CallExpert(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, coinID *common.Hash, value2 *big.Int) (ret []byte, leftOverGas uint64, err error) { + fmt.Println("CallExpert") + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + // Fail if we're trying to transfer more than the available balance + if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + return nil, gas, ErrInsufficientBalance + } + + var to = AccountRef(addr) + mcerr := evm.Context.CanTransferMC(evm.StateDB, caller.Address(), to.Address(), coinID, value2) + if mcerr == 1 { + return nil, gas, ErrInsufficientBalance + } else if mcerr != 0 { + return nil, gas, ErrIncompatibleAccount + } + + var snapshot = evm.StateDB.Snapshot() + + if !evm.StateDB.Exist(addr) { + precompiles := PrecompiledContractsHomestead + if evm.chainRules.IsByzantium { + precompiles = PrecompiledContractsByzantium + } + if evm.chainRules.IsIstanbul { + precompiles = PrecompiledContractsIstanbul + } + if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 { + // Calling a non existing account, don't do anything, but ping the tracer + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + } + return nil, gas, nil + } + evm.StateDB.CreateAccount(addr) + } + evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) + evm.TransferMultiCoin(evm.StateDB, caller.Address(), to.Address(), coinID, value2) + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, to, value, gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + // Even if the account has no code, we need to continue because it might be a precompile + start := time.Now() + + // Capture the tracer start/end events in debug mode + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + + defer func() { // Lazy evaluation of the parameters + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + }() + } + ret, err = run(evm, contract, input, false) + + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in homestead this also counts for code storage gas errors. + if err != nil { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + return ret, contract.Gas, err +} + +// CallCode executes the contract associated with the addr with the given input +// as parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. +// +// CallCode differs from Call in the sense that it executes the given address' +// code with the caller as context. +func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + // Fail if we're trying to transfer more than the available balance + if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { + return nil, gas, ErrInsufficientBalance + } + + var ( + snapshot = evm.StateDB.Snapshot() + to = AccountRef(caller.Address()) + ) + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, to, value, gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + ret, err = run(evm, contract, input, false) + if err != nil { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + return ret, contract.Gas, err +} + +// DelegateCall executes the contract associated with the addr with the given input +// as parameters. It reverses the state in case of an execution error. +// +// DelegateCall differs from CallCode in the sense that it executes the given address' +// code with the caller as context and the caller is set to the caller of the caller. +func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + + var ( + snapshot = evm.StateDB.Snapshot() + to = AccountRef(caller.Address()) + ) + + // Initialise a new contract and make initialise the delegate values + contract := NewContract(caller, to, nil, gas).AsDelegate() + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + ret, err = run(evm, contract, input, false) + if err != nil { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + return ret, contract.Gas, err +} + +// StaticCall executes the contract associated with the addr with the given input +// as parameters while disallowing any modifications to the state during the call. +// Opcodes that attempt to perform such modifications will result in exceptions +// instead of performing the modifications. +func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, to, new(big.Int), gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + // We do an AddBalance of zero here, just in order to trigger a touch. + // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, + // but is the correct thing to do and matters on other networks, in tests, and potential + // future scenarios + evm.StateDB.AddBalance(addr, bigZero) + + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in Homestead this also counts for code storage gas errors. + ret, err = run(evm, contract, input, true) + if err != nil { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + return ret, contract.Gas, err +} + +type codeAndHash struct { + code []byte + hash common.Hash +} + +func (c *codeAndHash) Hash() common.Hash { + if c.hash == (common.Hash{}) { + c.hash = crypto.Keccak256Hash(c.code) + } + return c.hash +} + +// create creates a new contract using code as deployment code. +func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { + // Depth check execution. Fail if we're trying to execute above the + // limit. + if evm.depth > int(params.CallCreateDepth) { + return nil, common.Address{}, gas, ErrDepth + } + if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { + return nil, common.Address{}, gas, ErrInsufficientBalance + } + nonce := evm.StateDB.GetNonce(caller.Address()) + evm.StateDB.SetNonce(caller.Address(), nonce+1) + + // Ensure there's no existing contract already at the designated address + contractHash := evm.StateDB.GetCodeHash(address) + if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { + return nil, common.Address{}, 0, ErrContractAddressCollision + } + // Create a new account on the state + snapshot := evm.StateDB.Snapshot() + evm.StateDB.CreateAccount(address) + if evm.chainRules.IsEIP158 { + evm.StateDB.SetNonce(address, 1) + } + evm.Transfer(evm.StateDB, caller.Address(), address, value) + + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, AccountRef(address), value, gas) + contract.SetCodeOptionalHash(&address, codeAndHash) + + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, address, gas, nil + } + + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) + } + start := time.Now() + + ret, err := run(evm, contract, nil, false) + + // check whether the max code size has been exceeded + maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize + // if the contract creation ran successfully and no errors were returned + // calculate the gas required to store the code. If the code could not + // be stored due to not enough gas set an error and let it be handled + // by the error checking condition below. + if err == nil && !maxCodeSizeExceeded { + createDataGas := uint64(len(ret)) * params.CreateDataGas + if contract.UseGas(createDataGas) { + evm.StateDB.SetCode(address, ret) + } else { + err = ErrCodeStoreOutOfGas + } + } + + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in homestead this also counts for code storage gas errors. + if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) { + evm.StateDB.RevertToSnapshot(snapshot) + if err != errExecutionReverted { + contract.UseGas(contract.Gas) + } + } + // Assign err if contract code size exceeds the max while the err is still empty. + if maxCodeSizeExceeded && err == nil { + err = errMaxCodeSizeExceeded + } + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + } + return ret, address, contract.Gas, err + +} + +// Create creates a new contract using code as deployment code. +func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) + return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) +} + +// Create2 creates a new contract using code as deployment code. +// +// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:] +// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. +func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + codeAndHash := &codeAndHash{code: code} + contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) + return evm.create(caller, codeAndHash, gas, endowment, contractAddr) +} + +// ChainConfig returns the environment's chain configuration +func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } diff --git a/core/vm/gas.go b/core/vm/gas.go new file mode 100644 index 0000000..bd8b4f1 --- /dev/null +++ b/core/vm/gas.go @@ -0,0 +1,53 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "math/big" +) + +// Gas costs +const ( + GasQuickStep uint64 = 2 + GasFastestStep uint64 = 3 + GasFastStep uint64 = 5 + GasMidStep uint64 = 8 + GasSlowStep uint64 = 10 + GasExtStep uint64 = 20 +) + +// calcGas returns the actual gas cost of the call. +// +// The cost of gas was changed during the homestead price change HF. +// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64. +func callGas(isEip150 bool, availableGas, base uint64, callCost *big.Int) (uint64, error) { + if isEip150 { + availableGas = availableGas - base + gas := availableGas - availableGas/64 + // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 + // is smaller than the requested amount. Therefor we return the new gas instead + // of returning an error. + if !callCost.IsUint64() || gas < callCost.Uint64() { + return gas, nil + } + } + if !callCost.IsUint64() { + return 0, errGasUintOverflow + } + + return callCost.Uint64(), nil +} diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go new file mode 100644 index 0000000..2adaf85 --- /dev/null +++ b/core/vm/gas_table.go @@ -0,0 +1,441 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "errors" + + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" +) + +// memoryGasCost calculates the quadratic gas for memory expansion. It does so +// only for the memory region that is expanded, not the total memory. +func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { + if newMemSize == 0 { + return 0, nil + } + // The maximum that will fit in a uint64 is max_word_count - 1. Anything above + // that will result in an overflow. Additionally, a newMemSize which results in + // a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to + // overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used + // without overflowing the gas calculation. + if newMemSize > 0x1FFFFFFFE0 { + return 0, errGasUintOverflow + } + newMemSizeWords := toWordSize(newMemSize) + newMemSize = newMemSizeWords * 32 + + if newMemSize > uint64(mem.Len()) { + square := newMemSizeWords * newMemSizeWords + linCoef := newMemSizeWords * params.MemoryGas + quadCoef := square / params.QuadCoeffDiv + newTotalFee := linCoef + quadCoef + + fee := newTotalFee - mem.lastGasCost + mem.lastGasCost = newTotalFee + + return fee, nil + } + return 0, nil +} + +// memoryCopierGas creates the gas functions for the following opcodes, and takes +// the stack position of the operand which determines the size of the data to copy +// as argument: +// CALLDATACOPY (stack position 2) +// CODECOPY (stack position 2) +// EXTCODECOPY (stack poition 3) +// RETURNDATACOPY (stack position 2) +func memoryCopierGas(stackpos int) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // Gas for expanding the memory + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + // And gas for copying data, charged per word at param.CopyGas + words, overflow := bigUint64(stack.Back(stackpos)) + if overflow { + return 0, errGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil + } +} + +var ( + gasCallDataCopy = memoryCopierGas(2) + gasCodeCopy = memoryCopierGas(2) + gasExtCodeCopy = memoryCopierGas(3) + gasReturnDataCopy = memoryCopierGas(2) +) + +func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + y, x = stack.Back(1), stack.Back(0) + current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) + ) + // The legacy gas metering only takes into consideration the current state + // Legacy rules should be applied if we are in Petersburg (removal of EIP-1283) + // OR Constantinople is not active + if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople { + // This checks for 3 scenario's and calculates gas accordingly: + // + // 1. From a zero-value address to a non-zero value (NEW VALUE) + // 2. From a non-zero value address to a zero-value address (DELETE) + // 3. From a non-zero to a non-zero (CHANGE) + switch { + case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 + return params.SstoreSetGas, nil + case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 + evm.StateDB.AddRefund(params.SstoreRefundGas) + return params.SstoreClearGas, nil + default: // non 0 => non 0 (or 0 => 0) + return params.SstoreResetGas, nil + } + } + // The new gas metering is based on net gas costs (EIP-1283): + // + // 1. If current value equals new value (this is a no-op), 200 gas is deducted. + // 2. If current value does not equal new value + // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context) + // 2.1.1. If original value is 0, 20000 gas is deducted. + // 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. + // 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. + // 2.2.1. If original value is not 0 + // 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. + // 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. + // 2.2.2. If original value equals new value (this storage slot is reset) + // 2.2.2.1. If original value is 0, add 19800 gas to refund counter. + // 2.2.2.2. Otherwise, add 4800 gas to refund counter. + value := common.BigToHash(y) + if current == value { // noop (1) + return params.NetSstoreNoopGas, nil + } + original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x)) + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return params.NetSstoreInitGas, nil + } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) + } + return params.NetSstoreCleanGas, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.NetSstoreClearRefund) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + evm.StateDB.AddRefund(params.NetSstoreResetClearRefund) + } else { // reset to original existing slot (2.2.2.2) + evm.StateDB.AddRefund(params.NetSstoreResetRefund) + } + } + return params.NetSstoreDirtyGas, nil +} + +// 0. If *gasleft* is less than or equal to 2300, fail the current call. +// 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS gas is deducted. +// 2. If current value does not equal new value: +// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context): +// 2.1.1. If original value is 0, SSTORE_INIT_GAS gas is deducted. +// 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter. +// 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses: +// 2.2.1. If original value is not 0: +// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEAR_REFUND gas from refund counter. We can prove that refund counter will never go below 0. +// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEAR_REFUND gas to refund counter. +// 2.2.2. If original value equals new value (this storage slot is reset): +// 2.2.2.1. If original value is 0, add SSTORE_INIT_REFUND to refund counter. +// 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND gas to refund counter. +func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // If we fail the minimum gas availability invariant, fail (0) + if contract.Gas <= params.SstoreSentryGasEIP2200 { + return 0, errors.New("not enough gas for reentrancy sentry") + } + // Gas sentry honoured, do the actual gas calculation based on the stored value + var ( + y, x = stack.Back(1), stack.Back(0) + current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) + ) + value := common.BigToHash(y) + + if current == value { // noop (1) + return params.SstoreNoopGasEIP2200, nil + } + original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x)) + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return params.SstoreInitGasEIP2200, nil + } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200) + } + return params.SstoreCleanGasEIP2200, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.SstoreClearRefundEIP2200) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200) + } else { // reset to original existing slot (2.2.2.2) + evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200) + } + } + return params.SstoreDirtyGasEIP2200, nil // dirty update (2.2) +} + +func makeGasLog(n uint64) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + requestedSize, overflow := bigUint64(stack.Back(1)) + if overflow { + return 0, errGasUintOverflow + } + + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + + if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { + return 0, errGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { + return 0, errGasUintOverflow + } + + var memorySizeGas uint64 + if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { + return 0, errGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil + } +} + +func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + wordGas, overflow := bigUint64(stack.Back(1)) + if overflow { + return 0, errGasUintOverflow + } + if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { + return 0, errGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, wordGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +// pureMemoryGascost is used by several operations, which aside from their +// static cost have a dynamic cost which is solely based on the memory +// expansion +func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return memoryGasCost(mem, memorySize) +} + +var ( + gasReturn = pureMemoryGascost + gasRevert = pureMemoryGascost + gasMLoad = pureMemoryGascost + gasMStore8 = pureMemoryGascost + gasMStore = pureMemoryGascost + gasCreate = pureMemoryGascost +) + +func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + wordGas, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { + return 0, errGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, wordGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) + + var ( + gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas + overflow bool + ) + if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) + + var ( + gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas + overflow bool + ) + if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + gas uint64 + transfersValue = stack.Back(2).Sign() != 0 + address = common.BigToAddress(stack.Back(1)) + ) + if evm.chainRules.IsEIP158 { + if transfersValue && evm.StateDB.Empty(address) { + gas += params.CallNewAccountGas + } + } else if !evm.StateDB.Exist(address) { + gas += params.CallNewAccountGas + } + if transfersValue { + gas += params.CallValueTransferGas + } + memoryGas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { + return 0, errGasUintOverflow + } + + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + memoryGas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var ( + gas uint64 + overflow bool + ) + if stack.Back(2).Sign() != 0 { + gas += params.CallValueTransferGas + } + if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { + return 0, errGasUintOverflow + } + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var gas uint64 + // EIP150 homestead gas reprice fork: + if evm.chainRules.IsEIP150 { + gas = params.SelfdestructGasEIP150 + var address = common.BigToAddress(stack.Back(0)) + + if evm.chainRules.IsEIP158 { + // if empty and transfers value + if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { + gas += params.CreateBySelfdestructGas + } + } else if !evm.StateDB.Exist(address) { + gas += params.CreateBySelfdestructGas + } + } + + if !evm.StateDB.HasSuicided(contract.Address()) { + evm.StateDB.AddRefund(params.SelfdestructRefundGas) + } + return gas, nil +} diff --git a/core/vm/gen_structlog.go b/core/vm/gen_structlog.go new file mode 100644 index 0000000..038841c --- /dev/null +++ b/core/vm/gen_structlog.go @@ -0,0 +1,111 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package vm + +import ( + "encoding/json" + "math/big" + + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/hexutil" + "github.com/ava-labs/go-ethereum/common/math" +) + +var _ = (*structLogMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s StructLog) MarshalJSON() ([]byte, error) { + type StructLog struct { + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas math.HexOrDecimal64 `json:"gas"` + GasCost math.HexOrDecimal64 `json:"gasCost"` + Memory hexutil.Bytes `json:"memory"` + MemorySize int `json:"memSize"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + RefundCounter uint64 `json:"refund"` + Err error `json:"-"` + OpName string `json:"opName"` + ErrorString string `json:"error"` + } + var enc StructLog + enc.Pc = s.Pc + enc.Op = s.Op + enc.Gas = math.HexOrDecimal64(s.Gas) + enc.GasCost = math.HexOrDecimal64(s.GasCost) + enc.Memory = s.Memory + enc.MemorySize = s.MemorySize + if s.Stack != nil { + enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack)) + for k, v := range s.Stack { + enc.Stack[k] = (*math.HexOrDecimal256)(v) + } + } + enc.Storage = s.Storage + enc.Depth = s.Depth + enc.RefundCounter = s.RefundCounter + enc.Err = s.Err + enc.OpName = s.OpName() + enc.ErrorString = s.ErrorString() + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *StructLog) UnmarshalJSON(input []byte) error { + type StructLog struct { + Pc *uint64 `json:"pc"` + Op *OpCode `json:"op"` + Gas *math.HexOrDecimal64 `json:"gas"` + GasCost *math.HexOrDecimal64 `json:"gasCost"` + Memory *hexutil.Bytes `json:"memory"` + MemorySize *int `json:"memSize"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth *int `json:"depth"` + RefundCounter *uint64 `json:"refund"` + Err error `json:"-"` + } + var dec StructLog + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Pc != nil { + s.Pc = *dec.Pc + } + if dec.Op != nil { + s.Op = *dec.Op + } + if dec.Gas != nil { + s.Gas = uint64(*dec.Gas) + } + if dec.GasCost != nil { + s.GasCost = uint64(*dec.GasCost) + } + if dec.Memory != nil { + s.Memory = *dec.Memory + } + if dec.MemorySize != nil { + s.MemorySize = *dec.MemorySize + } + if dec.Stack != nil { + s.Stack = make([]*big.Int, len(dec.Stack)) + for k, v := range dec.Stack { + s.Stack[k] = (*big.Int)(v) + } + } + if dec.Storage != nil { + s.Storage = dec.Storage + } + if dec.Depth != nil { + s.Depth = *dec.Depth + } + if dec.RefundCounter != nil { + s.RefundCounter = *dec.RefundCounter + } + if dec.Err != nil { + s.Err = dec.Err + } + return nil +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go new file mode 100644 index 0000000..91233b3 --- /dev/null +++ b/core/vm/instructions.go @@ -0,0 +1,1011 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" + "golang.org/x/crypto/sha3" +) + +var ( + bigZero = new(big.Int) + tt255 = math.BigPow(2, 255) + errWriteProtection = errors.New("evm: write protection") + errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") + errExecutionReverted = errors.New("evm: execution reverted") + errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") + errInvalidJump = errors.New("evm: invalid jump destination") +) + +func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + math.U256(y.Add(x, y)) + + interpreter.intPool.put(x) + return nil, nil +} + +func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + math.U256(y.Sub(x, y)) + + interpreter.intPool.put(x) + return nil, nil +} + +func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.pop() + stack.push(math.U256(x.Mul(x, y))) + + interpreter.intPool.put(y) + + return nil, nil +} + +func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + if y.Sign() != 0 { + math.U256(y.Div(x, y)) + } else { + y.SetUint64(0) + } + interpreter.intPool.put(x) + return nil, nil +} + +func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := math.S256(stack.pop()), math.S256(stack.pop()) + res := interpreter.intPool.getZero() + + if y.Sign() == 0 || x.Sign() == 0 { + stack.push(res) + } else { + if x.Sign() != y.Sign() { + res.Div(x.Abs(x), y.Abs(y)) + res.Neg(res) + } else { + res.Div(x.Abs(x), y.Abs(y)) + } + stack.push(math.U256(res)) + } + interpreter.intPool.put(x, y) + return nil, nil +} + +func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.pop() + if y.Sign() == 0 { + stack.push(x.SetUint64(0)) + } else { + stack.push(math.U256(x.Mod(x, y))) + } + interpreter.intPool.put(y) + return nil, nil +} + +func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := math.S256(stack.pop()), math.S256(stack.pop()) + res := interpreter.intPool.getZero() + + if y.Sign() == 0 { + stack.push(res) + } else { + if x.Sign() < 0 { + res.Mod(x.Abs(x), y.Abs(y)) + res.Neg(res) + } else { + res.Mod(x.Abs(x), y.Abs(y)) + } + stack.push(math.U256(res)) + } + interpreter.intPool.put(x, y) + return nil, nil +} + +func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + base, exponent := stack.pop(), stack.pop() + // some shortcuts + cmpToOne := exponent.Cmp(big1) + if cmpToOne < 0 { // Exponent is zero + // x ^ 0 == 1 + stack.push(base.SetUint64(1)) + } else if base.Sign() == 0 { + // 0 ^ y, if y != 0, == 0 + stack.push(base.SetUint64(0)) + } else if cmpToOne == 0 { // Exponent is one + // x ^ 1 == x + stack.push(base) + } else { + stack.push(math.Exp(base, exponent)) + interpreter.intPool.put(base) + } + interpreter.intPool.put(exponent) + return nil, nil +} + +func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + back := stack.pop() + if back.Cmp(big.NewInt(31)) < 0 { + bit := uint(back.Uint64()*8 + 7) + num := stack.pop() + mask := back.Lsh(common.Big1, bit) + mask.Sub(mask, common.Big1) + if num.Bit(int(bit)) > 0 { + num.Or(num, mask.Not(mask)) + } else { + num.And(num, mask) + } + + stack.push(math.U256(num)) + } + + interpreter.intPool.put(back) + return nil, nil +} + +func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x := stack.peek() + math.U256(x.Not(x)) + return nil, nil +} + +func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + if x.Cmp(y) < 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + interpreter.intPool.put(x) + return nil, nil +} + +func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + if x.Cmp(y) > 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + interpreter.intPool.put(x) + return nil, nil +} + +func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + + xSign := x.Cmp(tt255) + ySign := y.Cmp(tt255) + + switch { + case xSign >= 0 && ySign < 0: + y.SetUint64(1) + + case xSign < 0 && ySign >= 0: + y.SetUint64(0) + + default: + if x.Cmp(y) < 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + } + interpreter.intPool.put(x) + return nil, nil +} + +func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + + xSign := x.Cmp(tt255) + ySign := y.Cmp(tt255) + + switch { + case xSign >= 0 && ySign < 0: + y.SetUint64(0) + + case xSign < 0 && ySign >= 0: + y.SetUint64(1) + + default: + if x.Cmp(y) > 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + } + interpreter.intPool.put(x) + return nil, nil +} + +func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + if x.Cmp(y) == 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + interpreter.intPool.put(x) + return nil, nil +} + +func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x := stack.peek() + if x.Sign() > 0 { + x.SetUint64(0) + } else { + x.SetUint64(1) + } + return nil, nil +} + +func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.pop() + stack.push(x.And(x, y)) + + interpreter.intPool.put(y) + return nil, nil +} + +func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + y.Or(x, y) + + interpreter.intPool.put(x) + return nil, nil +} + +func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + y.Xor(x, y) + + interpreter.intPool.put(x) + return nil, nil +} + +func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + th, val := stack.pop(), stack.peek() + if th.Cmp(common.Big32) < 0 { + b := math.Byte(val, 32, int(th.Int64())) + val.SetUint64(uint64(b)) + } else { + val.SetUint64(0) + } + interpreter.intPool.put(th) + return nil, nil +} + +func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y, z := stack.pop(), stack.pop(), stack.pop() + if z.Cmp(bigZero) > 0 { + x.Add(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) + } else { + stack.push(x.SetUint64(0)) + } + interpreter.intPool.put(y, z) + return nil, nil +} + +func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y, z := stack.pop(), stack.pop(), stack.pop() + if z.Cmp(bigZero) > 0 { + x.Mul(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) + } else { + stack.push(x.SetUint64(0)) + } + interpreter.intPool.put(y, z) + return nil, nil +} + +// opSHL implements Shift Left +// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the left by arg1 number of bits. +func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards + shift, value := math.U256(stack.pop()), math.U256(stack.peek()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + value.SetUint64(0) + return nil, nil + } + n := uint(shift.Uint64()) + math.U256(value.Lsh(value, n)) + + return nil, nil +} + +// opSHR implements Logical Shift Right +// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. +func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards + shift, value := math.U256(stack.pop()), math.U256(stack.peek()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + value.SetUint64(0) + return nil, nil + } + n := uint(shift.Uint64()) + math.U256(value.Rsh(value, n)) + + return nil, nil +} + +// opSAR implements Arithmetic Shift Right +// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. +func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one + shift, value := math.U256(stack.pop()), math.S256(stack.pop()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + if value.Sign() >= 0 { + value.SetUint64(0) + } else { + value.SetInt64(-1) + } + stack.push(math.U256(value)) + return nil, nil + } + n := uint(shift.Uint64()) + value.Rsh(value, n) + stack.push(math.U256(value)) + + return nil, nil +} + +func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset, size := stack.pop(), stack.pop() + data := memory.Get(offset.Int64(), size.Int64()) + + if interpreter.hasher == nil { + interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) + } else { + interpreter.hasher.Reset() + } + interpreter.hasher.Write(data) + interpreter.hasher.Read(interpreter.hasherBuf[:]) + + evm := interpreter.evm + if evm.vmConfig.EnablePreimageRecording { + evm.StateDB.AddPreimage(interpreter.hasherBuf, data) + } + stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) + + interpreter.intPool.put(offset, size) + return nil, nil +} + +func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes())) + return nil, nil +} + +func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) + return nil, nil +} + +func opBalanceMultiCoin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + addr, cid := stack.pop(), stack.pop() + fmt.Println(addr, cid) + stack.push(interpreter.evm.StateDB.GetBalanceMultiCoin(common.BigToAddress(addr), common.BigToHash(cid))) + return nil, nil +} + +func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes())) + return nil, nil +} + +func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes())) + return nil, nil +} + +func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(contract.value)) + return nil, nil +} + +func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32))) + return nil, nil +} + +func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) + return nil, nil +} + +func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + memOffset = stack.pop() + dataOffset = stack.pop() + length = stack.pop() + ) + memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) + + interpreter.intPool.put(memOffset, dataOffset, length) + return nil, nil +} + +func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) + return nil, nil +} + +func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + memOffset = stack.pop() + dataOffset = stack.pop() + length = stack.pop() + + end = interpreter.intPool.get().Add(dataOffset, length) + ) + defer interpreter.intPool.put(memOffset, dataOffset, length, end) + + if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() { + return nil, errReturnDataOutOfBounds + } + memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) + + return nil, nil +} + +func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) + + return nil, nil +} + +func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + l := interpreter.intPool.get().SetInt64(int64(len(contract.Code))) + stack.push(l) + + return nil, nil +} + +func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() + ) + codeCopy := getDataBig(contract.Code, codeOffset, length) + memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + + interpreter.intPool.put(memOffset, codeOffset, length) + return nil, nil +} + +func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + addr = common.BigToAddress(stack.pop()) + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() + ) + codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) + memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + + interpreter.intPool.put(memOffset, codeOffset, length) + return nil, nil +} + +// opExtCodeHash returns the code hash of a specified account. +// There are several cases when the function is called, while we can relay everything +// to `state.GetCodeHash` function to ensure the correctness. +// (1) Caller tries to get the code hash of a normal contract account, state +// should return the relative code hash and set it as the result. +// +// (2) Caller tries to get the code hash of a non-existent account, state should +// return common.Hash{} and zero will be set as the result. +// +// (3) Caller tries to get the code hash for an account without contract code, +// state should return emptyCodeHash(0xc5d246...) as the result. +// +// (4) Caller tries to get the code hash of a precompiled account, the result +// should be zero or emptyCodeHash. +// +// It is worth noting that in order to avoid unnecessary create and clean, +// all precompile accounts on mainnet have been transferred 1 wei, so the return +// here should be emptyCodeHash. +// If the precompile account is not transferred any amount on a private or +// customized chain, the return value will be zero. +// +// (5) Caller tries to get the code hash for an account which is marked as suicided +// in the current transaction, the code hash of this account should be returned. +// +// (6) Caller tries to get the code hash for an account which is marked as deleted, +// this account should be regarded as a non-existent account and zero should be returned. +func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + address := common.BigToAddress(slot) + if interpreter.evm.StateDB.Empty(address) { + slot.SetUint64(0) + } else { + slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes()) + } + return nil, nil +} + +func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) + return nil, nil +} + +func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + num := stack.pop() + + n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) + if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { + stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) + } else { + stack.push(interpreter.intPool.getZero()) + } + interpreter.intPool.put(num, n) + return nil, nil +} + +func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) + return nil, nil +} + +func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) + return nil, nil +} + +func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) + return nil, nil +} + +func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) + return nil, nil +} + +func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) + return nil, nil +} + +func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + interpreter.intPool.put(stack.pop()) + return nil, nil +} + +func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset := stack.pop() + val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32)) + stack.push(val) + + interpreter.intPool.put(offset) + return nil, nil +} + +func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // pop value of the stack + mStart, val := stack.pop(), stack.pop() + memory.Set32(mStart.Uint64(), val) + + interpreter.intPool.put(mStart, val) + return nil, nil +} + +func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + off, val := stack.pop().Int64(), stack.pop().Int64() + memory.store[off] = byte(val & 0xff) + + return nil, nil +} + +func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + loc := stack.peek() + val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) + loc.SetBytes(val.Bytes()) + return nil, nil +} + +func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + loc := common.BigToHash(stack.pop()) + val := stack.pop() + if err := interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)); err != nil { + return nil, err + } + interpreter.intPool.put(val) + return nil, nil +} + +func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + pos := stack.pop() + if !contract.validJumpdest(pos) { + return nil, errInvalidJump + } + *pc = pos.Uint64() + + interpreter.intPool.put(pos) + return nil, nil +} + +func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + pos, cond := stack.pop(), stack.pop() + if cond.Sign() != 0 { + if !contract.validJumpdest(pos) { + return nil, errInvalidJump + } + *pc = pos.Uint64() + } else { + *pc++ + } + + interpreter.intPool.put(pos, cond) + return nil, nil +} + +func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return nil, nil +} + +func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(*pc)) + return nil, nil +} + +func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len()))) + return nil, nil +} + +func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(contract.Gas)) + return nil, nil +} + +func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + value = stack.pop() + offset, size = stack.pop(), stack.pop() + input = memory.Get(offset.Int64(), size.Int64()) + gas = contract.Gas + ) + if interpreter.evm.chainRules.IsEIP150 { + gas -= gas / 64 + } + + contract.UseGas(gas) + res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value) + // Push item on the stack based on the returned error. If the ruleset is + // homestead we must check for CodeStoreOutOfGasError (homestead only + // rule) and treat as an error, if the ruleset is frontier we must + // ignore this error and pretend the operation was successful. + if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { + stack.push(interpreter.intPool.getZero()) + } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) + } + contract.Gas += returnGas + interpreter.intPool.put(value, offset, size) + + if suberr == errExecutionReverted { + return res, nil + } + return nil, nil +} + +func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + endowment = stack.pop() + offset, size = stack.pop(), stack.pop() + salt = stack.pop() + input = memory.Get(offset.Int64(), size.Int64()) + gas = contract.Gas + ) + + // Apply EIP150 + gas -= gas / 64 + contract.UseGas(gas) + res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) + // Push item on the stack based on the returned error. + if suberr != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) + } + contract.Gas += returnGas + interpreter.intPool.put(endowment, offset, size, salt) + + if suberr == errExecutionReverted { + return res, nil + } + return nil, nil +} + +func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp + // Pop other call parameters. + addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + value = math.U256(value) + // Get the arguments from the memory. + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + if value.Sign() != 0 { + gas += params.CallStipend + } + ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) + if err != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetUint64(1)) + } + if err == nil || err == errExecutionReverted { + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + return ret, nil +} + +func opCallExpert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp + // Pop other call parameters. + addr, value, cid, value2, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + coinID := common.BigToHash(cid) + value = math.U256(value) + value2 = math.U256(value2) + // Get the arguments from the memory. + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + if value.Sign() != 0 { + gas += params.CallStipend + } + ret, returnGas, err := interpreter.evm.CallExpert(contract, toAddr, args, gas, value, &coinID, value2) + if err != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetUint64(1)) + } + if err == nil || err == errExecutionReverted { + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + return ret, nil +} + +func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp + // Pop other call parameters. + addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + value = math.U256(value) + // Get arguments from the memory. + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + if value.Sign() != 0 { + gas += params.CallStipend + } + ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) + if err != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetUint64(1)) + } + if err == nil || err == errExecutionReverted { + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + return ret, nil +} + +func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp + // Pop other call parameters. + addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + // Get arguments from the memory. + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) + if err != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetUint64(1)) + } + if err == nil || err == errExecutionReverted { + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + return ret, nil +} + +func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp + // Pop other call parameters. + addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + // Get arguments from the memory. + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) + if err != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(interpreter.intPool.get().SetUint64(1)) + } + if err == nil || err == errExecutionReverted { + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + return ret, nil +} + +func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset, size := stack.pop(), stack.pop() + ret := memory.GetPtr(offset.Int64(), size.Int64()) + + interpreter.intPool.put(offset, size) + return ret, nil +} + +func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset, size := stack.pop(), stack.pop() + ret := memory.GetPtr(offset.Int64(), size.Int64()) + + interpreter.intPool.put(offset, size) + return ret, nil +} + +func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return nil, nil +} + +func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + balance := interpreter.evm.StateDB.GetBalance(contract.Address()) + interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) + + interpreter.evm.StateDB.Suicide(contract.Address()) + return nil, nil +} + +func opEMC(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return nil, interpreter.evm.StateDB.EnableMultiCoin(contract.Address()) +} + +// following functions are used by the instruction jump table + +// make log instruction function +func makeLog(size int) executionFunc { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + topics := make([]common.Hash, size) + mStart, mSize := stack.pop(), stack.pop() + for i := 0; i < size; i++ { + topics[i] = common.BigToHash(stack.pop()) + } + + d := memory.Get(mStart.Int64(), mSize.Int64()) + interpreter.evm.StateDB.AddLog(&types.Log{ + Address: contract.Address(), + Topics: topics, + Data: d, + // This is a non-consensus field, but assigned here because + // core/state doesn't know the current block number. + BlockNumber: interpreter.evm.BlockNumber.Uint64(), + }) + + interpreter.intPool.put(mStart, mSize) + return nil, nil + } +} + +// opPush1 is a specialized version of pushN +func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + codeLen = uint64(len(contract.Code)) + integer = interpreter.intPool.get() + ) + *pc += 1 + if *pc < codeLen { + stack.push(integer.SetUint64(uint64(contract.Code[*pc]))) + } else { + stack.push(integer.SetUint64(0)) + } + return nil, nil +} + +// make push instruction function +func makePush(size uint64, pushByteSize int) executionFunc { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + codeLen := len(contract.Code) + + startMin := codeLen + if int(*pc+1) < startMin { + startMin = int(*pc + 1) + } + + endMin := codeLen + if startMin+pushByteSize < endMin { + endMin = startMin + pushByteSize + } + + integer := interpreter.intPool.get() + stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) + + *pc += size + return nil, nil + } +} + +// make dup instruction function +func makeDup(size int64) executionFunc { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.dup(interpreter.intPool, int(size)) + return nil, nil + } +} + +// make swap instruction function +func makeSwap(size int64) executionFunc { + // switch n + 1 otherwise n would be swapped with n + size++ + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.swap(int(size)) + return nil, nil + } +} diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go new file mode 100644 index 0000000..82fbfed --- /dev/null +++ b/core/vm/int_pool_verifier.go @@ -0,0 +1,31 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// +build VERIFY_EVM_INTEGER_POOL + +package vm + +import "fmt" + +const verifyPool = true + +func verifyIntegerPool(ip *intPool) { + for i, item := range ip.pool.data { + if item.Cmp(checkVal) != 0 { + panic(fmt.Sprintf("%d'th item failed aggressive pool check. Value was modified", i)) + } + } +} diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go new file mode 100644 index 0000000..a5f1dc0 --- /dev/null +++ b/core/vm/int_pool_verifier_empty.go @@ -0,0 +1,23 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// +build !VERIFY_EVM_INTEGER_POOL + +package vm + +const verifyPool = false + +func verifyIntegerPool(ip *intPool) {} diff --git a/core/vm/interface.go b/core/vm/interface.go new file mode 100644 index 0000000..7e2d324 --- /dev/null +++ b/core/vm/interface.go @@ -0,0 +1,87 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "math/big" + + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/go-ethereum/common" +) + +// StateDB is an EVM database for full state querying. +type StateDB interface { + CreateAccount(common.Address) + + SubBalance(common.Address, *big.Int) + AddBalance(common.Address, *big.Int) + GetBalance(common.Address) *big.Int + + SubBalanceMultiCoin(common.Address, common.Hash, *big.Int) + AddBalanceMultiCoin(common.Address, common.Hash, *big.Int) + GetBalanceMultiCoin(common.Address, common.Hash) *big.Int + EnableMultiCoin(common.Address) error + IsMultiCoin(common.Address) bool + + GetNonce(common.Address) uint64 + SetNonce(common.Address, uint64) + + GetCodeHash(common.Address) common.Hash + GetCode(common.Address) []byte + SetCode(common.Address, []byte) + GetCodeSize(common.Address) int + + AddRefund(uint64) + SubRefund(uint64) + GetRefund() uint64 + + GetCommittedState(common.Address, common.Hash) common.Hash + GetState(common.Address, common.Hash) common.Hash + SetState(common.Address, common.Hash, common.Hash) error + + Suicide(common.Address) bool + HasSuicided(common.Address) bool + + // Exist reports whether the given account exists in state. + // Notably this should also return true for suicided accounts. + Exist(common.Address) bool + // Empty returns whether the given account is empty. Empty + // is defined according to EIP161 (balance = nonce = code = 0). + Empty(common.Address) bool + + RevertToSnapshot(int) + Snapshot() int + + AddLog(*types.Log) + AddPreimage(common.Hash, []byte) + + ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error +} + +// CallContext provides a basic interface for the EVM calling conventions. The EVM +// depends on this context being implemented for doing subcalls and initialising new EVM contracts. +type CallContext interface { + // Call another contract + Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + CallExpert(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int, coinID *common.Hash, value2 *big.Int) ([]byte, error) + // Take another's contract code and execute within our own context + CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + // Same as CallCode except sender and value is propagated from parent to child scope + DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) + // Create a new contract + Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) +} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go new file mode 100644 index 0000000..007e5e3 --- /dev/null +++ b/core/vm/interpreter.go @@ -0,0 +1,300 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" + "hash" + "sync/atomic" + + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" + "github.com/ava-labs/go-ethereum/log" +) + +// Config are the configuration options for the Interpreter +type Config struct { + Debug bool // Enables debugging + Tracer Tracer // Opcode logger + NoRecursion bool // Disables call, callcode, delegate call and create + EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages + + JumpTable [256]operation // EVM instruction table, automatically populated if unset + + EWASMInterpreter string // External EWASM interpreter options + EVMInterpreter string // External EVM interpreter options + + ExtraEips []int // Additional EIPS that are to be enabled +} + +// Interpreter is used to run Ethereum based contracts and will utilise the +// passed environment to query external sources for state information. +// The Interpreter will run the byte code VM based on the passed +// configuration. +type Interpreter interface { + // Run loops and evaluates the contract's code with the given input data and returns + // the return byte-slice and an error if one occurred. + Run(contract *Contract, input []byte, static bool) ([]byte, error) + // CanRun tells if the contract, passed as an argument, can be + // run by the current interpreter. This is meant so that the + // caller can do something like: + // + // ```golang + // for _, interpreter := range interpreters { + // if interpreter.CanRun(contract.code) { + // interpreter.Run(contract.code, input) + // } + // } + // ``` + CanRun([]byte) bool +} + +// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports +// Read to get a variable amount of data from the hash state. Read is faster than Sum +// because it doesn't copy the internal state, but also modifies the internal state. +type keccakState interface { + hash.Hash + Read([]byte) (int, error) +} + +// EVMInterpreter represents an EVM interpreter +type EVMInterpreter struct { + evm *EVM + cfg Config + + intPool *intPool + + hasher keccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes + + readOnly bool // Whether to throw on stateful modifications + returnData []byte // Last CALL's return data for subsequent reuse +} + +// NewEVMInterpreter returns a new instance of the Interpreter. +func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { + // We use the STOP instruction whether to see + // the jump table was initialised. If it was not + // we'll set the default jump table. + if !cfg.JumpTable[STOP].valid { + var jt JumpTable + switch { + case evm.chainRules.IsIstanbul: + jt = istanbulInstructionSet + case evm.chainRules.IsConstantinople: + jt = constantinopleInstructionSet + case evm.chainRules.IsByzantium: + jt = byzantiumInstructionSet + case evm.chainRules.IsEIP158: + jt = spuriousDragonInstructionSet + case evm.chainRules.IsEIP150: + jt = tangerineWhistleInstructionSet + case evm.chainRules.IsHomestead: + jt = homesteadInstructionSet + default: + jt = frontierInstructionSet + } + for i, eip := range cfg.ExtraEips { + if err := EnableEIP(eip, &jt); err != nil { + // Disable it, so caller can check if it's activated or not + cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) + log.Error("EIP activation failed", "eip", eip, "error", err) + } + } + cfg.JumpTable = jt + } + + return &EVMInterpreter{ + evm: evm, + cfg: cfg, + } +} + +// Run loops and evaluates the contract's code with the given input data and returns +// the return byte-slice and an error if one occurred. +// +// It's important to note that any errors returned by the interpreter should be +// considered a revert-and-consume-all-gas operation except for +// errExecutionReverted which means revert-and-keep-gas-left. +func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { + if in.intPool == nil { + in.intPool = poolOfIntPools.get() + defer func() { + poolOfIntPools.put(in.intPool) + in.intPool = nil + }() + } + + // Increment the call depth which is restricted to 1024 + in.evm.depth++ + defer func() { in.evm.depth-- }() + + // Make sure the readOnly is only set if we aren't in readOnly yet. + // This makes also sure that the readOnly flag isn't removed for child calls. + if readOnly && !in.readOnly { + in.readOnly = true + defer func() { in.readOnly = false }() + } + + // Reset the previous call's return data. It's unimportant to preserve the old buffer + // as every returning call will return new data anyway. + in.returnData = nil + + // Don't bother with the execution if there's no code. + if len(contract.Code) == 0 { + return nil, nil + } + + var ( + op OpCode // current opcode + mem = NewMemory() // bound memory + stack = newstack() // local stack + // For optimisation reason we're using uint64 as the program counter. + // It's theoretically possible to go above 2^64. The YP defines the PC + // to be uint256. Practically much less so feasible. + pc = uint64(0) // program counter + cost uint64 + // copies used by tracer + pcCopy uint64 // needed for the deferred Tracer + gasCopy uint64 // for Tracer to log gas remaining before execution + logged bool // deferred Tracer should ignore already logged steps + res []byte // result of the opcode execution function + ) + contract.Input = input + + // Reclaim the stack as an int pool when the execution stops + defer func() { in.intPool.put(stack.data...) }() + + if in.cfg.Debug { + defer func() { + if err != nil { + if !logged { + in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + } else { + in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + } + } + }() + } + // The Interpreter main run loop (contextual). This loop runs until either an + // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during + // the execution of one of the operations or until the done flag is set by the + // parent context. + for atomic.LoadInt32(&in.evm.abort) == 0 { + if in.cfg.Debug { + // Capture pre-execution values for tracing. + logged, pcCopy, gasCopy = false, pc, contract.Gas + } + + // Get the operation from the jump table and validate the stack to ensure there are + // enough stack items available to perform the operation. + op = contract.GetOp(pc) + operation := in.cfg.JumpTable[op] + if !operation.valid { + return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) + } + // Validate stack + if sLen := stack.len(); sLen < operation.minStack { + return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack) + } else if sLen > operation.maxStack { + return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack) + } + // If the operation is valid, enforce and write restrictions + if in.readOnly && in.evm.chainRules.IsByzantium { + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item + // for a call operation is the value. Transferring value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) { + return nil, errWriteProtection + } + } + // Static portion of gas + cost = operation.constantGas // For tracing + if !contract.UseGas(operation.constantGas) { + return nil, ErrOutOfGas + } + + var memorySize uint64 + // calculate the new memory size and expand the memory to fit + // the operation + // Memory check needs to be done prior to evaluating the dynamic gas portion, + // to detect calculation overflows + if operation.memorySize != nil { + memSize, overflow := operation.memorySize(stack) + if overflow { + return nil, errGasUintOverflow + } + // memory is expanded in words of 32 bytes. Gas + // is also calculated in words. + if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { + return nil, errGasUintOverflow + } + } + // Dynamic portion of gas + // consume the gas and return an error if not enough gas is available. + // cost is explicitly set so that the capture state defer method can get the proper cost + if operation.dynamicGas != nil { + var dynamicCost uint64 + dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) + cost += dynamicCost // total cost, for debug tracing + if err != nil || !contract.UseGas(dynamicCost) { + return nil, ErrOutOfGas + } + } + if memorySize > 0 { + mem.Resize(memorySize) + } + + if in.cfg.Debug { + in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + logged = true + } + + // execute the operation + res, err = operation.execute(&pc, in, contract, mem, stack) + // verifyPool is a build flag. Pool verification makes sure the integrity + // of the integer pool by comparing values to a default value. + if verifyPool { + verifyIntegerPool(in.intPool) + } + // if the operation clears the return data (e.g. it has returning data) + // set the last return to the result of the operation. + if operation.returns { + in.returnData = res + } + + switch { + case err != nil: + return nil, err + case operation.reverts: + return res, errExecutionReverted + case operation.halts: + return res, nil + case !operation.jumps: + pc++ + } + } + return nil, nil +} + +// CanRun tells if the contract, passed as an argument, can be +// run by the current interpreter. +func (in *EVMInterpreter) CanRun(code []byte) bool { + return true +} diff --git a/core/vm/intpool.go b/core/vm/intpool.go new file mode 100644 index 0000000..917a78d --- /dev/null +++ b/core/vm/intpool.go @@ -0,0 +1,106 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "math/big" + "sync" +) + +var checkVal = big.NewInt(-42) + +const poolLimit = 256 + +// intPool is a pool of big integers that +// can be reused for all big.Int operations. +type intPool struct { + pool *Stack +} + +func newIntPool() *intPool { + return &intPool{pool: newstack()} +} + +// get retrieves a big int from the pool, allocating one if the pool is empty. +// Note, the returned int's value is arbitrary and will not be zeroed! +func (p *intPool) get() *big.Int { + if p.pool.len() > 0 { + return p.pool.pop() + } + return new(big.Int) +} + +// getZero retrieves a big int from the pool, setting it to zero or allocating +// a new one if the pool is empty. +func (p *intPool) getZero() *big.Int { + if p.pool.len() > 0 { + return p.pool.pop().SetUint64(0) + } + return new(big.Int) +} + +// put returns an allocated big int to the pool to be later reused by get calls. +// Note, the values as saved as is; neither put nor get zeroes the ints out! +func (p *intPool) put(is ...*big.Int) { + if len(p.pool.data) > poolLimit { + return + } + for _, i := range is { + // verifyPool is a build flag. Pool verification makes sure the integrity + // of the integer pool by comparing values to a default value. + if verifyPool { + i.Set(checkVal) + } + p.pool.push(i) + } +} + +// The intPool pool's default capacity +const poolDefaultCap = 25 + +// intPoolPool manages a pool of intPools. +type intPoolPool struct { + pools []*intPool + lock sync.Mutex +} + +var poolOfIntPools = &intPoolPool{ + pools: make([]*intPool, 0, poolDefaultCap), +} + +// get is looking for an available pool to return. +func (ipp *intPoolPool) get() *intPool { + ipp.lock.Lock() + defer ipp.lock.Unlock() + + if len(poolOfIntPools.pools) > 0 { + ip := ipp.pools[len(ipp.pools)-1] + ipp.pools = ipp.pools[:len(ipp.pools)-1] + return ip + } + return newIntPool() +} + +// put a pool that has been allocated with get. +func (ipp *intPoolPool) put(ip *intPool) { + ipp.lock.Lock() + defer ipp.lock.Unlock() + + if len(ipp.pools) < cap(ipp.pools) { + ipp.pools = append(ipp.pools, ip) + } +} diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go new file mode 100644 index 0000000..359b753 --- /dev/null +++ b/core/vm/jump_table.go @@ -0,0 +1,1183 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "errors" + + "github.com/ava-labs/coreth/params" +) + +type ( + executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + // memorySizeFunc returns the required size, and whether the operation overflowed a uint64 + memorySizeFunc func(*Stack) (size uint64, overflow bool) +) + +var errGasUintOverflow = errors.New("gas uint64 overflow") + +type operation struct { + // execute is the operation function + execute executionFunc + constantGas uint64 + dynamicGas gasFunc + // minStack tells how many stack items are required + minStack int + // maxStack specifies the max length the stack can have for this operation + // to not overflow the stack. + maxStack int + + // memorySize returns the memory size required for the operation + memorySize memorySizeFunc + + halts bool // indicates whether the operation should halt further execution + jumps bool // indicates whether the program counter should not increment + writes bool // determines whether this a state modifying operation + valid bool // indication whether the retrieved operation is valid and known + reverts bool // determines whether the operation reverts state (implicitly halts) + returns bool // determines whether the operations sets the return data content +} + +var ( + frontierInstructionSet = newFrontierInstructionSet() + homesteadInstructionSet = newHomesteadInstructionSet() + tangerineWhistleInstructionSet = newTangerineWhistleInstructionSet() + spuriousDragonInstructionSet = newSpuriousDragonInstructionSet() + byzantiumInstructionSet = newByzantiumInstructionSet() + constantinopleInstructionSet = newConstantinopleInstructionSet() + istanbulInstructionSet = newIstanbulInstructionSet() +) + +// JumpTable contains the EVM opcodes supported at a given fork. +type JumpTable [256]operation + +// newIstanbulInstructionSet returns the frontier, homestead +// byzantium, contantinople and petersburg instructions. +func newIstanbulInstructionSet() JumpTable { + instructionSet := newConstantinopleInstructionSet() + + enable1344(&instructionSet) // ChainID opcode - https://eips.ethereum.org/EIPS/eip-1344 + enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884 + enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200 + + return instructionSet +} + +// newConstantinopleInstructionSet returns the frontier, homestead +// byzantium and contantinople instructions. +func newConstantinopleInstructionSet() JumpTable { + instructionSet := newByzantiumInstructionSet() + instructionSet[SHL] = operation{ + execute: opSHL, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + } + instructionSet[SHR] = operation{ + execute: opSHR, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + } + instructionSet[SAR] = operation{ + execute: opSAR, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + } + instructionSet[EXTCODEHASH] = operation{ + execute: opExtCodeHash, + constantGas: params.ExtcodeHashGasConstantinople, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + } + instructionSet[CREATE2] = operation{ + execute: opCreate2, + constantGas: params.Create2Gas, + dynamicGas: gasCreate2, + minStack: minStack(4, 1), + maxStack: maxStack(4, 1), + memorySize: memoryCreate2, + valid: true, + writes: true, + returns: true, + } + return instructionSet +} + +// newByzantiumInstructionSet returns the frontier, homestead and +// byzantium instructions. +func newByzantiumInstructionSet() JumpTable { + instructionSet := newSpuriousDragonInstructionSet() + instructionSet[STATICCALL] = operation{ + execute: opStaticCall, + constantGas: params.CallGasEIP150, + dynamicGas: gasStaticCall, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryStaticCall, + valid: true, + returns: true, + } + instructionSet[RETURNDATASIZE] = operation{ + execute: opReturnDataSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + } + instructionSet[RETURNDATACOPY] = operation{ + execute: opReturnDataCopy, + constantGas: GasFastestStep, + dynamicGas: gasReturnDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + } + instructionSet[REVERT] = operation{ + execute: opRevert, + dynamicGas: gasRevert, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryRevert, + valid: true, + reverts: true, + returns: true, + } + return instructionSet +} + +// EIP 158 a.k.a Spurious Dragon +func newSpuriousDragonInstructionSet() JumpTable { + instructionSet := newTangerineWhistleInstructionSet() + instructionSet[EXP].dynamicGas = gasExpEIP158 + return instructionSet + +} + +// EIP 150 a.k.a Tangerine Whistle +func newTangerineWhistleInstructionSet() JumpTable { + instructionSet := newHomesteadInstructionSet() + instructionSet[BALANCE].constantGas = params.BalanceGasEIP150 + instructionSet[EXTCODESIZE].constantGas = params.ExtcodeSizeGasEIP150 + instructionSet[SLOAD].constantGas = params.SloadGasEIP150 + instructionSet[EXTCODECOPY].constantGas = params.ExtcodeCopyBaseEIP150 + instructionSet[CALL].constantGas = params.CallGasEIP150 + instructionSet[CALLCODE].constantGas = params.CallGasEIP150 + instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 + return instructionSet +} + +// newHomesteadInstructionSet returns the frontier and homestead +// instructions that can be executed during the homestead phase. +func newHomesteadInstructionSet() JumpTable { + instructionSet := newFrontierInstructionSet() + instructionSet[DELEGATECALL] = operation{ + execute: opDelegateCall, + dynamicGas: gasDelegateCall, + constantGas: params.CallGasFrontier, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryDelegateCall, + valid: true, + returns: true, + } + return instructionSet +} + +// newFrontierInstructionSet returns the frontier instructions +// that can be executed during the frontier phase. +func newFrontierInstructionSet() JumpTable { + return JumpTable{ + STOP: { + execute: opStop, + constantGas: 0, + minStack: minStack(0, 0), + maxStack: maxStack(0, 0), + halts: true, + valid: true, + }, + ADD: { + execute: opAdd, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + MUL: { + execute: opMul, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SUB: { + execute: opSub, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + DIV: { + execute: opDiv, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SDIV: { + execute: opSdiv, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + MOD: { + execute: opMod, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SMOD: { + execute: opSmod, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + ADDMOD: { + execute: opAddmod, + constantGas: GasMidStep, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + valid: true, + }, + MULMOD: { + execute: opMulmod, + constantGas: GasMidStep, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + valid: true, + }, + EXP: { + execute: opExp, + dynamicGas: gasExpFrontier, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SIGNEXTEND: { + execute: opSignExtend, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + LT: { + execute: opLt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + GT: { + execute: opGt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SLT: { + execute: opSlt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SGT: { + execute: opSgt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + EQ: { + execute: opEq, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + ISZERO: { + execute: opIszero, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + AND: { + execute: opAnd, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + XOR: { + execute: opXor, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + OR: { + execute: opOr, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + NOT: { + execute: opNot, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + BYTE: { + execute: opByte, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + SHA3: { + execute: opSha3, + constantGas: params.Sha3Gas, + dynamicGas: gasSha3, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + memorySize: memorySha3, + valid: true, + }, + ADDRESS: { + execute: opAddress, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + BALANCE: { + execute: opBalance, + constantGas: params.BalanceGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + BALANCEMC: { + execute: opBalanceMultiCoin, + constantGas: params.BalanceGasFrontier, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, + }, + ORIGIN: { + execute: opOrigin, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + CALLER: { + execute: opCaller, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + CALLVALUE: { + execute: opCallValue, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + CALLDATALOAD: { + execute: opCallDataLoad, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + CALLDATASIZE: { + execute: opCallDataSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + CALLDATACOPY: { + execute: opCallDataCopy, + constantGas: GasFastestStep, + dynamicGas: gasCallDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCallDataCopy, + valid: true, + }, + CODESIZE: { + execute: opCodeSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + CODECOPY: { + execute: opCodeCopy, + constantGas: GasFastestStep, + dynamicGas: gasCodeCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCodeCopy, + valid: true, + }, + GASPRICE: { + execute: opGasprice, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + EXTCODESIZE: { + execute: opExtCodeSize, + constantGas: params.ExtcodeSizeGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + EXTCODECOPY: { + execute: opExtCodeCopy, + constantGas: params.ExtcodeCopyBaseFrontier, + dynamicGas: gasExtCodeCopy, + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryExtCodeCopy, + valid: true, + }, + BLOCKHASH: { + execute: opBlockhash, + constantGas: GasExtStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + COINBASE: { + execute: opCoinbase, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + TIMESTAMP: { + execute: opTimestamp, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + NUMBER: { + execute: opNumber, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + DIFFICULTY: { + execute: opDifficulty, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + GASLIMIT: { + execute: opGasLimit, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + POP: { + execute: opPop, + constantGas: GasQuickStep, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + valid: true, + }, + MLOAD: { + execute: opMload, + constantGas: GasFastestStep, + dynamicGas: gasMLoad, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + memorySize: memoryMLoad, + valid: true, + }, + MSTORE: { + execute: opMstore, + constantGas: GasFastestStep, + dynamicGas: gasMStore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryMStore, + valid: true, + }, + MSTORE8: { + execute: opMstore8, + constantGas: GasFastestStep, + dynamicGas: gasMStore8, + memorySize: memoryMStore8, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + + valid: true, + }, + SLOAD: { + execute: opSload, + constantGas: params.SloadGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, + }, + SSTORE: { + execute: opSstore, + dynamicGas: gasSStore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + valid: true, + writes: true, + }, + JUMP: { + execute: opJump, + constantGas: GasMidStep, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + jumps: true, + valid: true, + }, + JUMPI: { + execute: opJumpi, + constantGas: GasSlowStep, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + jumps: true, + valid: true, + }, + PC: { + execute: opPc, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + MSIZE: { + execute: opMsize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + GAS: { + execute: opGas, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + JUMPDEST: { + execute: opJumpdest, + constantGas: params.JumpdestGas, + minStack: minStack(0, 0), + maxStack: maxStack(0, 0), + valid: true, + }, + EMC: { + execute: opEMC, + constantGas: params.EMCGas, + minStack: minStack(0, 0), + maxStack: maxStack(0, 0), + valid: true, + }, + PUSH1: { + execute: opPush1, + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH2: { + execute: makePush(2, 2), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH3: { + execute: makePush(3, 3), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH4: { + execute: makePush(4, 4), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH5: { + execute: makePush(5, 5), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH6: { + execute: makePush(6, 6), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH7: { + execute: makePush(7, 7), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH8: { + execute: makePush(8, 8), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH9: { + execute: makePush(9, 9), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH10: { + execute: makePush(10, 10), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH11: { + execute: makePush(11, 11), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH12: { + execute: makePush(12, 12), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH13: { + execute: makePush(13, 13), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH14: { + execute: makePush(14, 14), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH15: { + execute: makePush(15, 15), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH16: { + execute: makePush(16, 16), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH17: { + execute: makePush(17, 17), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH18: { + execute: makePush(18, 18), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH19: { + execute: makePush(19, 19), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH20: { + execute: makePush(20, 20), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH21: { + execute: makePush(21, 21), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH22: { + execute: makePush(22, 22), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH23: { + execute: makePush(23, 23), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH24: { + execute: makePush(24, 24), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH25: { + execute: makePush(25, 25), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH26: { + execute: makePush(26, 26), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH27: { + execute: makePush(27, 27), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH28: { + execute: makePush(28, 28), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH29: { + execute: makePush(29, 29), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH30: { + execute: makePush(30, 30), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH31: { + execute: makePush(31, 31), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + PUSH32: { + execute: makePush(32, 32), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, + }, + DUP1: { + execute: makeDup(1), + constantGas: GasFastestStep, + minStack: minDupStack(1), + maxStack: maxDupStack(1), + valid: true, + }, + DUP2: { + execute: makeDup(2), + constantGas: GasFastestStep, + minStack: minDupStack(2), + maxStack: maxDupStack(2), + valid: true, + }, + DUP3: { + execute: makeDup(3), + constantGas: GasFastestStep, + minStack: minDupStack(3), + maxStack: maxDupStack(3), + valid: true, + }, + DUP4: { + execute: makeDup(4), + constantGas: GasFastestStep, + minStack: minDupStack(4), + maxStack: maxDupStack(4), + valid: true, + }, + DUP5: { + execute: makeDup(5), + constantGas: GasFastestStep, + minStack: minDupStack(5), + maxStack: maxDupStack(5), + valid: true, + }, + DUP6: { + execute: makeDup(6), + constantGas: GasFastestStep, + minStack: minDupStack(6), + maxStack: maxDupStack(6), + valid: true, + }, + DUP7: { + execute: makeDup(7), + constantGas: GasFastestStep, + minStack: minDupStack(7), + maxStack: maxDupStack(7), + valid: true, + }, + DUP8: { + execute: makeDup(8), + constantGas: GasFastestStep, + minStack: minDupStack(8), + maxStack: maxDupStack(8), + valid: true, + }, + DUP9: { + execute: makeDup(9), + constantGas: GasFastestStep, + minStack: minDupStack(9), + maxStack: maxDupStack(9), + valid: true, + }, + DUP10: { + execute: makeDup(10), + constantGas: GasFastestStep, + minStack: minDupStack(10), + maxStack: maxDupStack(10), + valid: true, + }, + DUP11: { + execute: makeDup(11), + constantGas: GasFastestStep, + minStack: minDupStack(11), + maxStack: maxDupStack(11), + valid: true, + }, + DUP12: { + execute: makeDup(12), + constantGas: GasFastestStep, + minStack: minDupStack(12), + maxStack: maxDupStack(12), + valid: true, + }, + DUP13: { + execute: makeDup(13), + constantGas: GasFastestStep, + minStack: minDupStack(13), + maxStack: maxDupStack(13), + valid: true, + }, + DUP14: { + execute: makeDup(14), + constantGas: GasFastestStep, + minStack: minDupStack(14), + maxStack: maxDupStack(14), + valid: true, + }, + DUP15: { + execute: makeDup(15), + constantGas: GasFastestStep, + minStack: minDupStack(15), + maxStack: maxDupStack(15), + valid: true, + }, + DUP16: { + execute: makeDup(16), + constantGas: GasFastestStep, + minStack: minDupStack(16), + maxStack: maxDupStack(16), + valid: true, + }, + SWAP1: { + execute: makeSwap(1), + constantGas: GasFastestStep, + minStack: minSwapStack(2), + maxStack: maxSwapStack(2), + valid: true, + }, + SWAP2: { + execute: makeSwap(2), + constantGas: GasFastestStep, + minStack: minSwapStack(3), + maxStack: maxSwapStack(3), + valid: true, + }, + SWAP3: { + execute: makeSwap(3), + constantGas: GasFastestStep, + minStack: minSwapStack(4), + maxStack: maxSwapStack(4), + valid: true, + }, + SWAP4: { + execute: makeSwap(4), + constantGas: GasFastestStep, + minStack: minSwapStack(5), + maxStack: maxSwapStack(5), + valid: true, + }, + SWAP5: { + execute: makeSwap(5), + constantGas: GasFastestStep, + minStack: minSwapStack(6), + maxStack: maxSwapStack(6), + valid: true, + }, + SWAP6: { + execute: makeSwap(6), + constantGas: GasFastestStep, + minStack: minSwapStack(7), + maxStack: maxSwapStack(7), + valid: true, + }, + SWAP7: { + execute: makeSwap(7), + constantGas: GasFastestStep, + minStack: minSwapStack(8), + maxStack: maxSwapStack(8), + valid: true, + }, + SWAP8: { + execute: makeSwap(8), + constantGas: GasFastestStep, + minStack: minSwapStack(9), + maxStack: maxSwapStack(9), + valid: true, + }, + SWAP9: { + execute: makeSwap(9), + constantGas: GasFastestStep, + minStack: minSwapStack(10), + maxStack: maxSwapStack(10), + valid: true, + }, + SWAP10: { + execute: makeSwap(10), + constantGas: GasFastestStep, + minStack: minSwapStack(11), + maxStack: maxSwapStack(11), + valid: true, + }, + SWAP11: { + execute: makeSwap(11), + constantGas: GasFastestStep, + minStack: minSwapStack(12), + maxStack: maxSwapStack(12), + valid: true, + }, + SWAP12: { + execute: makeSwap(12), + constantGas: GasFastestStep, + minStack: minSwapStack(13), + maxStack: maxSwapStack(13), + valid: true, + }, + SWAP13: { + execute: makeSwap(13), + constantGas: GasFastestStep, + minStack: minSwapStack(14), + maxStack: maxSwapStack(14), + valid: true, + }, + SWAP14: { + execute: makeSwap(14), + constantGas: GasFastestStep, + minStack: minSwapStack(15), + maxStack: maxSwapStack(15), + valid: true, + }, + SWAP15: { + execute: makeSwap(15), + constantGas: GasFastestStep, + minStack: minSwapStack(16), + maxStack: maxSwapStack(16), + valid: true, + }, + SWAP16: { + execute: makeSwap(16), + constantGas: GasFastestStep, + minStack: minSwapStack(17), + maxStack: maxSwapStack(17), + valid: true, + }, + LOG0: { + execute: makeLog(0), + dynamicGas: makeGasLog(0), + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryLog, + valid: true, + writes: true, + }, + LOG1: { + execute: makeLog(1), + dynamicGas: makeGasLog(1), + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryLog, + valid: true, + writes: true, + }, + LOG2: { + execute: makeLog(2), + dynamicGas: makeGasLog(2), + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryLog, + valid: true, + writes: true, + }, + LOG3: { + execute: makeLog(3), + dynamicGas: makeGasLog(3), + minStack: minStack(5, 0), + maxStack: maxStack(5, 0), + memorySize: memoryLog, + valid: true, + writes: true, + }, + LOG4: { + execute: makeLog(4), + dynamicGas: makeGasLog(4), + minStack: minStack(6, 0), + maxStack: maxStack(6, 0), + memorySize: memoryLog, + valid: true, + writes: true, + }, + CREATE: { + execute: opCreate, + constantGas: params.CreateGas, + dynamicGas: gasCreate, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + memorySize: memoryCreate, + valid: true, + writes: true, + returns: true, + }, + CALL: { + execute: opCall, + constantGas: params.CallGasFrontier, + dynamicGas: gasCall, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, + }, + CALLEX: { + execute: opCallExpert, + constantGas: params.CallGasFrontier, + dynamicGas: gasCall, + minStack: minStack(9, 1), + maxStack: maxStack(9, 1), + memorySize: memoryCall, + valid: true, + returns: true, + }, + CALLCODE: { + execute: opCallCode, + constantGas: params.CallGasFrontier, + dynamicGas: gasCallCode, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, + }, + RETURN: { + execute: opReturn, + dynamicGas: gasReturn, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryReturn, + halts: true, + valid: true, + }, + SELFDESTRUCT: { + execute: opSuicide, + dynamicGas: gasSelfdestruct, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + halts: true, + valid: true, + writes: true, + }, + } +} diff --git a/core/vm/logger.go b/core/vm/logger.go new file mode 100644 index 0000000..95143f1 --- /dev/null +++ b/core/vm/logger.go @@ -0,0 +1,256 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "encoding/hex" + "fmt" + "io" + "math/big" + "time" + + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/hexutil" + "github.com/ava-labs/go-ethereum/common/math" +) + +// Storage represents a contract's storage. +type Storage map[common.Hash]common.Hash + +// Copy duplicates the current storage. +func (s Storage) Copy() Storage { + cpy := make(Storage) + for key, value := range s { + cpy[key] = value + } + + return cpy +} + +// LogConfig are the configuration options for structured logger the EVM +type LogConfig struct { + DisableMemory bool // disable memory capture + DisableStack bool // disable stack capture + DisableStorage bool // disable storage capture + Debug bool // print output during capture end + Limit int // maximum length of output, but zero means unlimited +} + +//go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go + +// StructLog is emitted to the EVM each cycle and lists information about the current internal state +// prior to the execution of the statement. +type StructLog struct { + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Memory []byte `json:"memory"` + MemorySize int `json:"memSize"` + Stack []*big.Int `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + RefundCounter uint64 `json:"refund"` + Err error `json:"-"` +} + +// overrides for gencodec +type structLogMarshaling struct { + Stack []*math.HexOrDecimal256 + Gas math.HexOrDecimal64 + GasCost math.HexOrDecimal64 + Memory hexutil.Bytes + OpName string `json:"opName"` // adds call to OpName() in MarshalJSON + ErrorString string `json:"error"` // adds call to ErrorString() in MarshalJSON +} + +// OpName formats the operand name in a human-readable format. +func (s *StructLog) OpName() string { + return s.Op.String() +} + +// ErrorString formats the log's error as a string. +func (s *StructLog) ErrorString() string { + if s.Err != nil { + return s.Err.Error() + } + return "" +} + +// Tracer is used to collect execution traces from an EVM transaction +// execution. CaptureState is called for each step of the VM with the +// current VM state. +// Note that reference types are actual VM data structures; make copies +// if you need to retain them beyond the current call. +type Tracer interface { + CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error + CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error +} + +// StructLogger is an EVM state logger and implements Tracer. +// +// StructLogger can capture state based on the given Log configuration and also keeps +// a track record of modified storage which is used in reporting snapshots of the +// contract their storage. +type StructLogger struct { + cfg LogConfig + + logs []StructLog + changedValues map[common.Address]Storage + output []byte + err error +} + +// NewStructLogger returns a new logger +func NewStructLogger(cfg *LogConfig) *StructLogger { + logger := &StructLogger{ + changedValues: make(map[common.Address]Storage), + } + if cfg != nil { + logger.cfg = *cfg + } + return logger +} + +// CaptureStart implements the Tracer interface to initialize the tracing operation. +func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error { + return nil +} + +// CaptureState logs a new structured log message and pushes it out to the environment +// +// CaptureState also tracks SSTORE ops to track dirty values. +func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + // check if already accumulated the specified number of logs + if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { + return ErrTraceLimitReached + } + + // initialise new changed values storage container for this contract + // if not present. + if l.changedValues[contract.Address()] == nil { + l.changedValues[contract.Address()] = make(Storage) + } + + // capture SSTORE opcodes and determine the changed value and store + // it in the local storage container. + if op == SSTORE && stack.len() >= 2 { + var ( + value = common.BigToHash(stack.data[stack.len()-2]) + address = common.BigToHash(stack.data[stack.len()-1]) + ) + l.changedValues[contract.Address()][address] = value + } + // Copy a snapshot of the current memory state to a new buffer + var mem []byte + if !l.cfg.DisableMemory { + mem = make([]byte, len(memory.Data())) + copy(mem, memory.Data()) + } + // Copy a snapshot of the current stack state to a new buffer + var stck []*big.Int + if !l.cfg.DisableStack { + stck = make([]*big.Int, len(stack.Data())) + for i, item := range stack.Data() { + stck[i] = new(big.Int).Set(item) + } + } + // Copy a snapshot of the current storage to a new container + var storage Storage + if !l.cfg.DisableStorage { + storage = l.changedValues[contract.Address()].Copy() + } + // create a new snapshot of the EVM. + log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, env.StateDB.GetRefund(), err} + + l.logs = append(l.logs, log) + return nil +} + +// CaptureFault implements the Tracer interface to trace an execution fault +// while running an opcode. +func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + return nil +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { + l.output = output + l.err = err + if l.cfg.Debug { + fmt.Printf("0x%x\n", output) + if err != nil { + fmt.Printf(" error: %v\n", err) + } + } + return nil +} + +// StructLogs returns the captured log entries. +func (l *StructLogger) StructLogs() []StructLog { return l.logs } + +// Error returns the VM error captured by the trace. +func (l *StructLogger) Error() error { return l.err } + +// Output returns the VM return value captured by the trace. +func (l *StructLogger) Output() []byte { return l.output } + +// WriteTrace writes a formatted trace to the given writer +func WriteTrace(writer io.Writer, logs []StructLog) { + for _, log := range logs { + fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost) + if log.Err != nil { + fmt.Fprintf(writer, " ERROR: %v", log.Err) + } + fmt.Fprintln(writer) + + if len(log.Stack) > 0 { + fmt.Fprintln(writer, "Stack:") + for i := len(log.Stack) - 1; i >= 0; i-- { + fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32)) + } + } + if len(log.Memory) > 0 { + fmt.Fprintln(writer, "Memory:") + fmt.Fprint(writer, hex.Dump(log.Memory)) + } + if len(log.Storage) > 0 { + fmt.Fprintln(writer, "Storage:") + for h, item := range log.Storage { + fmt.Fprintf(writer, "%x: %x\n", h, item) + } + } + fmt.Fprintln(writer) + } +} + +// WriteLogs writes vm logs in a readable format to the given writer +func WriteLogs(writer io.Writer, logs []*types.Log) { + for _, log := range logs { + fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex) + + for i, topic := range log.Topics { + fmt.Fprintf(writer, "%08d %x\n", i, topic) + } + + fmt.Fprint(writer, hex.Dump(log.Data)) + fmt.Fprintln(writer) + } +} diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go new file mode 100644 index 0000000..5068343 --- /dev/null +++ b/core/vm/logger_json.go @@ -0,0 +1,87 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "encoding/json" + "io" + "math/big" + "time" + + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/math" +) + +type JSONLogger struct { + encoder *json.Encoder + cfg *LogConfig +} + +// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects +// into the provided stream. +func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger { + l := &JSONLogger{json.NewEncoder(writer), cfg} + if l.cfg == nil { + l.cfg = &LogConfig{} + } + return l +} + +func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error { + return nil +} + +// CaptureState outputs state information on the logger. +func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + log := StructLog{ + Pc: pc, + Op: op, + Gas: gas, + GasCost: cost, + MemorySize: memory.Len(), + Storage: nil, + Depth: depth, + RefundCounter: env.StateDB.GetRefund(), + Err: err, + } + if !l.cfg.DisableMemory { + log.Memory = memory.Data() + } + if !l.cfg.DisableStack { + log.Stack = stack.Data() + } + return l.encoder.Encode(log) +} + +// CaptureFault outputs state information on the logger. +func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + return nil +} + +// CaptureEnd is triggered at end of execution. +func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { + type endLog struct { + Output string `json:"output"` + GasUsed math.HexOrDecimal64 `json:"gasUsed"` + Time time.Duration `json:"time"` + Err string `json:"error,omitempty"` + } + if err != nil { + return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()}) + } + return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""}) +} diff --git a/core/vm/memory.go b/core/vm/memory.go new file mode 100644 index 0000000..5408707 --- /dev/null +++ b/core/vm/memory.go @@ -0,0 +1,124 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" + "math/big" + + "github.com/ava-labs/go-ethereum/common/math" +) + +// Memory implements a simple memory model for the ethereum virtual machine. +type Memory struct { + store []byte + lastGasCost uint64 +} + +// NewMemory returns a new memory model. +func NewMemory() *Memory { + return &Memory{} +} + +// Set sets offset + size to value +func (m *Memory) Set(offset, size uint64, value []byte) { + // It's possible the offset is greater than 0 and size equals 0. This is because + // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP) + if size > 0 { + // length of store may never be less than offset + size. + // The store should be resized PRIOR to setting the memory + if offset+size > uint64(len(m.store)) { + panic("invalid memory: store empty") + } + copy(m.store[offset:offset+size], value) + } +} + +// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to +// 32 bytes. +func (m *Memory) Set32(offset uint64, val *big.Int) { + // length of store may never be less than offset + size. + // The store should be resized PRIOR to setting the memory + if offset+32 > uint64(len(m.store)) { + panic("invalid memory: store empty") + } + // Zero the memory area + copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + // Fill in relevant bits + math.ReadBits(val, m.store[offset:offset+32]) +} + +// Resize resizes the memory to size +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + +// Get returns offset + size as a new slice +func (m *Memory) Get(offset, size int64) (cpy []byte) { + if size == 0 { + return nil + } + + if len(m.store) > int(offset) { + cpy = make([]byte, size) + copy(cpy, m.store[offset:offset+size]) + + return + } + + return +} + +// GetPtr returns the offset + size +func (m *Memory) GetPtr(offset, size int64) []byte { + if size == 0 { + return nil + } + + if len(m.store) > int(offset) { + return m.store[offset : offset+size] + } + + return nil +} + +// Len returns the length of the backing slice +func (m *Memory) Len() int { + return len(m.store) +} + +// Data returns the backing slice +func (m *Memory) Data() []byte { + return m.store +} + +// Print dumps the content of the memory. +func (m *Memory) Print() { + fmt.Printf("### mem %d bytes ###\n", len(m.store)) + if len(m.store) > 0 { + addr := 0 + for i := 0; i+32 <= len(m.store); i += 32 { + fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) + addr++ + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("####################") +} diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go new file mode 100644 index 0000000..4fcb414 --- /dev/null +++ b/core/vm/memory_table.go @@ -0,0 +1,113 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +func memorySha3(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) +} + +func memoryCallDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) +} + +func memoryReturnDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) +} + +func memoryCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) +} + +func memoryExtCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(3)) +} + +func memoryMLoad(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) +} + +func memoryMStore8(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 1) +} + +func memoryMStore(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) +} + +func memoryCreate(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) +} + +func memoryCreate2(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) +} + +func memoryCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(5), stack.Back(6)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(3), stack.Back(4)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} +func memoryDelegateCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} + +func memoryStaticCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} + +func memoryReturn(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) +} + +func memoryRevert(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) +} + +func memoryLog(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) +} diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go new file mode 100644 index 0000000..1a66ef8 --- /dev/null +++ b/core/vm/opcodes.go @@ -0,0 +1,555 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" +) + +// OpCode is an EVM opcode +type OpCode byte + +// IsPush specifies if an opcode is a PUSH opcode. +func (op OpCode) IsPush() bool { + switch op { + case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: + return true + } + return false +} + +// IsStaticJump specifies if an opcode is JUMP. +func (op OpCode) IsStaticJump() bool { + return op == JUMP +} + +// 0x0 range - arithmetic ops. +const ( + STOP OpCode = iota + ADD + MUL + SUB + DIV + SDIV + MOD + SMOD + ADDMOD + MULMOD + EXP + SIGNEXTEND +) + +// 0x10 range - comparison ops. +const ( + LT OpCode = iota + 0x10 + GT + SLT + SGT + EQ + ISZERO + AND + OR + XOR + NOT + BYTE + SHL + SHR + SAR + + SHA3 = 0x20 +) + +// 0x30 range - closure state. +const ( + ADDRESS OpCode = 0x30 + iota + BALANCE + ORIGIN + CALLER + CALLVALUE + CALLDATALOAD + CALLDATASIZE + CALLDATACOPY + CODESIZE + CODECOPY + GASPRICE + EXTCODESIZE + EXTCODECOPY + RETURNDATASIZE + RETURNDATACOPY + EXTCODEHASH +) + +// 0x40 range - block operations. +const ( + BLOCKHASH OpCode = 0x40 + iota + COINBASE + TIMESTAMP + NUMBER + DIFFICULTY + GASLIMIT + CHAINID = 0x46 + SELFBALANCE = 0x47 +) + +// 0x50 range - 'storage' and execution. +const ( + POP OpCode = 0x50 + iota + MLOAD + MSTORE + MSTORE8 + SLOAD + SSTORE + JUMP + JUMPI + PC + MSIZE + GAS + JUMPDEST + EMC = 0x5c + BALANCEMC = 0x5d +) + +// 0x60 range. +const ( + PUSH1 OpCode = 0x60 + iota + PUSH2 + PUSH3 + PUSH4 + PUSH5 + PUSH6 + PUSH7 + PUSH8 + PUSH9 + PUSH10 + PUSH11 + PUSH12 + PUSH13 + PUSH14 + PUSH15 + PUSH16 + PUSH17 + PUSH18 + PUSH19 + PUSH20 + PUSH21 + PUSH22 + PUSH23 + PUSH24 + PUSH25 + PUSH26 + PUSH27 + PUSH28 + PUSH29 + PUSH30 + PUSH31 + PUSH32 + DUP1 + DUP2 + DUP3 + DUP4 + DUP5 + DUP6 + DUP7 + DUP8 + DUP9 + DUP10 + DUP11 + DUP12 + DUP13 + DUP14 + DUP15 + DUP16 + SWAP1 + SWAP2 + SWAP3 + SWAP4 + SWAP5 + SWAP6 + SWAP7 + SWAP8 + SWAP9 + SWAP10 + SWAP11 + SWAP12 + SWAP13 + SWAP14 + SWAP15 + SWAP16 +) + +// 0xa0 range - logging ops. +const ( + LOG0 OpCode = 0xa0 + iota + LOG1 + LOG2 + LOG3 + LOG4 +) + +// unofficial opcodes used for parsing. +const ( + PUSH OpCode = 0xb0 + iota + DUP + SWAP +) + +// 0xf0 range - closures. +const ( + CREATE OpCode = 0xf0 + iota + CALL + CALLCODE + RETURN + DELEGATECALL + CREATE2 + CALLEX = 0xf6 + STATICCALL = 0xfa + + REVERT = 0xfd + SELFDESTRUCT = 0xff +) + +// Since the opcodes aren't all in order we can't use a regular slice. +var opCodeToString = map[OpCode]string{ + // 0x0 range - arithmetic ops. + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NOT: "NOT", + LT: "LT", + GT: "GT", + SLT: "SLT", + SGT: "SGT", + EQ: "EQ", + ISZERO: "ISZERO", + SIGNEXTEND: "SIGNEXTEND", + + // 0x10 range - bit ops. + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", + SHL: "SHL", + SHR: "SHR", + SAR: "SAR", + ADDMOD: "ADDMOD", + MULMOD: "MULMOD", + + // 0x20 range - crypto. + SHA3: "SHA3", + + // 0x30 range - closure state. + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + BALANCEMC: "BALANCEMC", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", + GASPRICE: "GASPRICE", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", + RETURNDATASIZE: "RETURNDATASIZE", + RETURNDATACOPY: "RETURNDATACOPY", + EXTCODEHASH: "EXTCODEHASH", + + // 0x40 range - block operations. + BLOCKHASH: "BLOCKHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + CHAINID: "CHAINID", + SELFBALANCE: "SELFBALANCE", + + // 0x50 range - 'storage' and execution. + POP: "POP", + //DUP: "DUP", + //SWAP: "SWAP", + MLOAD: "MLOAD", + MSTORE: "MSTORE", + MSTORE8: "MSTORE8", + SLOAD: "SLOAD", + SSTORE: "SSTORE", + JUMP: "JUMP", + JUMPI: "JUMPI", + PC: "PC", + MSIZE: "MSIZE", + GAS: "GAS", + JUMPDEST: "JUMPDEST", + EMC: "EMC", + + // 0x60 range - push. + PUSH1: "PUSH1", + PUSH2: "PUSH2", + PUSH3: "PUSH3", + PUSH4: "PUSH4", + PUSH5: "PUSH5", + PUSH6: "PUSH6", + PUSH7: "PUSH7", + PUSH8: "PUSH8", + PUSH9: "PUSH9", + PUSH10: "PUSH10", + PUSH11: "PUSH11", + PUSH12: "PUSH12", + PUSH13: "PUSH13", + PUSH14: "PUSH14", + PUSH15: "PUSH15", + PUSH16: "PUSH16", + PUSH17: "PUSH17", + PUSH18: "PUSH18", + PUSH19: "PUSH19", + PUSH20: "PUSH20", + PUSH21: "PUSH21", + PUSH22: "PUSH22", + PUSH23: "PUSH23", + PUSH24: "PUSH24", + PUSH25: "PUSH25", + PUSH26: "PUSH26", + PUSH27: "PUSH27", + PUSH28: "PUSH28", + PUSH29: "PUSH29", + PUSH30: "PUSH30", + PUSH31: "PUSH31", + PUSH32: "PUSH32", + + DUP1: "DUP1", + DUP2: "DUP2", + DUP3: "DUP3", + DUP4: "DUP4", + DUP5: "DUP5", + DUP6: "DUP6", + DUP7: "DUP7", + DUP8: "DUP8", + DUP9: "DUP9", + DUP10: "DUP10", + DUP11: "DUP11", + DUP12: "DUP12", + DUP13: "DUP13", + DUP14: "DUP14", + DUP15: "DUP15", + DUP16: "DUP16", + + SWAP1: "SWAP1", + SWAP2: "SWAP2", + SWAP3: "SWAP3", + SWAP4: "SWAP4", + SWAP5: "SWAP5", + SWAP6: "SWAP6", + SWAP7: "SWAP7", + SWAP8: "SWAP8", + SWAP9: "SWAP9", + SWAP10: "SWAP10", + SWAP11: "SWAP11", + SWAP12: "SWAP12", + SWAP13: "SWAP13", + SWAP14: "SWAP14", + SWAP15: "SWAP15", + SWAP16: "SWAP16", + LOG0: "LOG0", + LOG1: "LOG1", + LOG2: "LOG2", + LOG3: "LOG3", + LOG4: "LOG4", + + // 0xf0 range. + CREATE: "CREATE", + CALL: "CALL", + CALLEX: "CALLEX", + RETURN: "RETURN", + CALLCODE: "CALLCODE", + DELEGATECALL: "DELEGATECALL", + CREATE2: "CREATE2", + STATICCALL: "STATICCALL", + REVERT: "REVERT", + SELFDESTRUCT: "SELFDESTRUCT", + + PUSH: "PUSH", + DUP: "DUP", + SWAP: "SWAP", +} + +func (op OpCode) String() string { + str := opCodeToString[op] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(op)) + } + + return str +} + +var stringToOp = map[string]OpCode{ + "STOP": STOP, + "ADD": ADD, + "MUL": MUL, + "SUB": SUB, + "DIV": DIV, + "SDIV": SDIV, + "MOD": MOD, + "SMOD": SMOD, + "EXP": EXP, + "NOT": NOT, + "LT": LT, + "GT": GT, + "SLT": SLT, + "SGT": SGT, + "EQ": EQ, + "ISZERO": ISZERO, + "SIGNEXTEND": SIGNEXTEND, + "AND": AND, + "OR": OR, + "XOR": XOR, + "BYTE": BYTE, + "SHL": SHL, + "SHR": SHR, + "SAR": SAR, + "ADDMOD": ADDMOD, + "MULMOD": MULMOD, + "SHA3": SHA3, + "ADDRESS": ADDRESS, + "BALANCE": BALANCE, + "BALANCEMC": BALANCEMC, + "ORIGIN": ORIGIN, + "CALLER": CALLER, + "CALLVALUE": CALLVALUE, + "CALLDATALOAD": CALLDATALOAD, + "CALLDATASIZE": CALLDATASIZE, + "CALLDATACOPY": CALLDATACOPY, + "CHAINID": CHAINID, + "DELEGATECALL": DELEGATECALL, + "STATICCALL": STATICCALL, + "CODESIZE": CODESIZE, + "CODECOPY": CODECOPY, + "GASPRICE": GASPRICE, + "EXTCODESIZE": EXTCODESIZE, + "EXTCODECOPY": EXTCODECOPY, + "RETURNDATASIZE": RETURNDATASIZE, + "RETURNDATACOPY": RETURNDATACOPY, + "EXTCODEHASH": EXTCODEHASH, + "BLOCKHASH": BLOCKHASH, + "COINBASE": COINBASE, + "TIMESTAMP": TIMESTAMP, + "NUMBER": NUMBER, + "DIFFICULTY": DIFFICULTY, + "GASLIMIT": GASLIMIT, + "SELFBALANCE": SELFBALANCE, + "POP": POP, + "MLOAD": MLOAD, + "MSTORE": MSTORE, + "MSTORE8": MSTORE8, + "SLOAD": SLOAD, + "SSTORE": SSTORE, + "JUMP": JUMP, + "JUMPI": JUMPI, + "PC": PC, + "MSIZE": MSIZE, + "GAS": GAS, + "JUMPDEST": JUMPDEST, + "EMC": EMC, + "PUSH1": PUSH1, + "PUSH2": PUSH2, + "PUSH3": PUSH3, + "PUSH4": PUSH4, + "PUSH5": PUSH5, + "PUSH6": PUSH6, + "PUSH7": PUSH7, + "PUSH8": PUSH8, + "PUSH9": PUSH9, + "PUSH10": PUSH10, + "PUSH11": PUSH11, + "PUSH12": PUSH12, + "PUSH13": PUSH13, + "PUSH14": PUSH14, + "PUSH15": PUSH15, + "PUSH16": PUSH16, + "PUSH17": PUSH17, + "PUSH18": PUSH18, + "PUSH19": PUSH19, + "PUSH20": PUSH20, + "PUSH21": PUSH21, + "PUSH22": PUSH22, + "PUSH23": PUSH23, + "PUSH24": PUSH24, + "PUSH25": PUSH25, + "PUSH26": PUSH26, + "PUSH27": PUSH27, + "PUSH28": PUSH28, + "PUSH29": PUSH29, + "PUSH30": PUSH30, + "PUSH31": PUSH31, + "PUSH32": PUSH32, + "DUP1": DUP1, + "DUP2": DUP2, + "DUP3": DUP3, + "DUP4": DUP4, + "DUP5": DUP5, + "DUP6": DUP6, + "DUP7": DUP7, + "DUP8": DUP8, + "DUP9": DUP9, + "DUP10": DUP10, + "DUP11": DUP11, + "DUP12": DUP12, + "DUP13": DUP13, + "DUP14": DUP14, + "DUP15": DUP15, + "DUP16": DUP16, + "SWAP1": SWAP1, + "SWAP2": SWAP2, + "SWAP3": SWAP3, + "SWAP4": SWAP4, + "SWAP5": SWAP5, + "SWAP6": SWAP6, + "SWAP7": SWAP7, + "SWAP8": SWAP8, + "SWAP9": SWAP9, + "SWAP10": SWAP10, + "SWAP11": SWAP11, + "SWAP12": SWAP12, + "SWAP13": SWAP13, + "SWAP14": SWAP14, + "SWAP15": SWAP15, + "SWAP16": SWAP16, + "LOG0": LOG0, + "LOG1": LOG1, + "LOG2": LOG2, + "LOG3": LOG3, + "LOG4": LOG4, + "CREATE": CREATE, + "CREATE2": CREATE2, + "CALL": CALL, + "CALLEX": CALLEX, + "RETURN": RETURN, + "CALLCODE": CALLCODE, + "REVERT": REVERT, + "SELFDESTRUCT": SELFDESTRUCT, +} + +// StringToOp finds the opcode whose name is stored in `str`. +func StringToOp(str string) OpCode { + return stringToOp[str] +} diff --git a/core/vm/stack.go b/core/vm/stack.go new file mode 100644 index 0000000..4c1b9e8 --- /dev/null +++ b/core/vm/stack.go @@ -0,0 +1,95 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "fmt" + "math/big" +) + +// Stack is an object for basic stack operations. Items popped to the stack are +// expected to be changed and modified. stack does not take care of adding newly +// initialised objects. +type Stack struct { + data []*big.Int +} + +func newstack() *Stack { + return &Stack{data: make([]*big.Int, 0, 1024)} +} + +// Data returns the underlying big.Int array. +func (st *Stack) Data() []*big.Int { + return st.data +} + +func (st *Stack) push(d *big.Int) { + // NOTE push limit (1024) is checked in baseCheck + //stackItem := new(big.Int).Set(d) + //st.data = append(st.data, stackItem) + st.data = append(st.data, d) +} +func (st *Stack) pushN(ds ...*big.Int) { + st.data = append(st.data, ds...) +} + +func (st *Stack) pop() (ret *big.Int) { + ret = st.data[len(st.data)-1] + st.data = st.data[:len(st.data)-1] + return +} + +func (st *Stack) len() int { + return len(st.data) +} + +func (st *Stack) swap(n int) { + st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] +} + +func (st *Stack) dup(pool *intPool, n int) { + st.push(pool.get().Set(st.data[st.len()-n])) +} + +func (st *Stack) peek() *big.Int { + return st.data[st.len()-1] +} + +// Back returns the n'th item in stack +func (st *Stack) Back(n int) *big.Int { + return st.data[st.len()-n-1] +} + +func (st *Stack) require(n int) error { + if st.len() < n { + return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n) + } + return nil +} + +// Print dumps the content of the stack +func (st *Stack) Print() { + fmt.Println("### stack ###") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("#############") +} diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go new file mode 100644 index 0000000..192d024 --- /dev/null +++ b/core/vm/stack_table.go @@ -0,0 +1,42 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "github.com/ava-labs/coreth/params" +) + +func minSwapStack(n int) int { + return minStack(n, n) +} +func maxSwapStack(n int) int { + return maxStack(n, n) +} + +func minDupStack(n int) int { + return minStack(n, n+1) +} +func maxDupStack(n int) int { + return maxStack(n, n+1) +} + +func maxStack(pop, push int) int { + return int(params.StackLimit) + pop - push +} +func minStack(pops, push int) int { + return pops +} -- cgit v1.2.3-70-g09d2 From 7feec02902d52a3abf722613eb9e218e015b723c Mon Sep 17 00:00:00 2001 From: Determinant Date: Tue, 30 Jun 2020 17:05:50 -0400 Subject: make mc tx work --- core/evm.go | 7 +- core/gen_genesis.go | 2 + core/gen_genesis_account.go | 8 + core/genesis.go | 9 + core/state/statedb.go | 5 + core/tx_pool.go | 1 - core/types/gen_tx_json.go | 12 + core/types/transaction.go | 22 +- core/vm/evm.go | 2 - eth/backend.go | 2 - eth/gen_config.go | 12 + eth/tracers/internal/tracers/assets.go | 37 +-- examples/chain/main.go | 2 +- examples/counter/main.go | 2 +- examples/multicoin/main.go | 218 +++++++++++++ plugin/evm/static_service_test.go | 64 ---- plugin/evm/vm_genesis_parse_test.go | 32 -- rpc/client_example_test.go | 88 ----- rpc/client_test.go | 569 --------------------------------- rpc/http_test.go | 54 ---- rpc/server_test.go | 152 --------- rpc/subscription_test.go | 206 ------------ rpc/testservice_test.go | 180 ----------- rpc/types_test.go | 66 ---- rpc/websocket_test.go | 259 --------------- 25 files changed, 297 insertions(+), 1714 deletions(-) create mode 100644 examples/multicoin/main.go delete mode 100644 plugin/evm/static_service_test.go delete mode 100644 plugin/evm/vm_genesis_parse_test.go delete mode 100644 rpc/client_example_test.go delete mode 100644 rpc/client_test.go delete mode 100644 rpc/http_test.go delete mode 100644 rpc/server_test.go delete mode 100644 rpc/subscription_test.go delete mode 100644 rpc/testservice_test.go delete mode 100644 rpc/types_test.go delete mode 100644 rpc/websocket_test.go (limited to 'core/vm') diff --git a/core/evm.go b/core/evm.go index ecab8e6..796b312 100644 --- a/core/evm.go +++ b/core/evm.go @@ -99,7 +99,7 @@ func CanTransferMC(db vm.StateDB, addr common.Address, to common.Address, coinID } if !db.IsMultiCoin(addr) { err := db.EnableMultiCoin(addr) - log.Debug("try to enable MC", "err", err) + log.Debug("try to enable MC", "addr", addr.Hex(), "err", err) } if !(db.IsMultiCoin(addr) && db.IsMultiCoin(to)) { // incompatible @@ -124,8 +124,5 @@ func TransferMultiCoin(db vm.StateDB, sender, recipient common.Address, coinID * return } db.SubBalanceMultiCoin(sender, *coinID, amount) - z := &big.Int{} - z.Add(amount, big.NewInt(1000000000000000000)) - log.Info("hi") - db.AddBalanceMultiCoin(recipient, *coinID, z) + db.AddBalanceMultiCoin(recipient, *coinID, amount) } diff --git a/core/gen_genesis.go b/core/gen_genesis.go index 05883c0..97175f7 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -15,6 +15,7 @@ import ( var _ = (*genesisSpecMarshaling)(nil) +// MarshalJSON marshals as JSON. func (g Genesis) MarshalJSON() ([]byte, error) { type Genesis struct { Config *params.ChainConfig `json:"config"` @@ -51,6 +52,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (g *Genesis) UnmarshalJSON(input []byte) error { type Genesis struct { Config *params.ChainConfig `json:"config"` diff --git a/core/gen_genesis_account.go b/core/gen_genesis_account.go index a7ef4a6..b90b658 100644 --- a/core/gen_genesis_account.go +++ b/core/gen_genesis_account.go @@ -14,11 +14,13 @@ import ( var _ = (*genesisAccountMarshaling)(nil) +// MarshalJSON marshals as JSON. func (g GenesisAccount) MarshalJSON() ([]byte, error) { type GenesisAccount struct { Code hexutil.Bytes `json:"code,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` + MCBalance GenesisMultiCoinBalance `json:"mcbalance,omitempty"` Nonce math.HexOrDecimal64 `json:"nonce,omitempty"` PrivateKey hexutil.Bytes `json:"secretKey,omitempty"` } @@ -31,16 +33,19 @@ func (g GenesisAccount) MarshalJSON() ([]byte, error) { } } enc.Balance = (*math.HexOrDecimal256)(g.Balance) + enc.MCBalance = g.MCBalance enc.Nonce = math.HexOrDecimal64(g.Nonce) enc.PrivateKey = g.PrivateKey return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (g *GenesisAccount) UnmarshalJSON(input []byte) error { type GenesisAccount struct { Code *hexutil.Bytes `json:"code,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` + MCBalance *GenesisMultiCoinBalance `json:"mcbalance,omitempty"` Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"` PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"` } @@ -61,6 +66,9 @@ func (g *GenesisAccount) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'balance' for GenesisAccount") } g.Balance = (*big.Int)(dec.Balance) + if dec.MCBalance != nil { + g.MCBalance = *dec.MCBalance + } if dec.Nonce != nil { g.Nonce = uint64(*dec.Nonce) } diff --git a/core/genesis.go b/core/genesis.go index 347beb3..ef490bf 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -78,11 +78,14 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { return nil } +type GenesisMultiCoinBalance map[common.Hash]*big.Int + // GenesisAccount is an account in the state of the genesis block. type GenesisAccount struct { Code []byte `json:"code,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"` Balance *big.Int `json:"balance" gencodec:"required"` + MCBalance GenesisMultiCoinBalance `json:"mcbalance,omitempty"` Nonce uint64 `json:"nonce,omitempty"` PrivateKey []byte `json:"secretKey,omitempty"` // for tests } @@ -261,6 +264,12 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { for key, value := range account.Storage { statedb.SetState(addr, key, value) } + if account.MCBalance != nil { + statedb.ForceEnableMultiCoin(addr) + for coinID, value := range account.MCBalance { + statedb.AddBalanceMultiCoin(addr, coinID, value) + } + } } root := statedb.IntermediateRoot(false) head := &types.Header{ diff --git a/core/state/statedb.go b/core/state/statedb.go index 12deebe..1d3207d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -248,6 +248,11 @@ func (self *StateDB) EnableMultiCoin(addr common.Address) error { return nil } +func (self *StateDB) ForceEnableMultiCoin(addr common.Address) { + stateObject := self.GetOrNewStateObject(addr) + stateObject.EnableMultiCoin() +} + func (self *StateDB) IsMultiCoin(addr common.Address) bool { stateObject := self.getStateObject(addr) if stateObject != nil { diff --git a/core/tx_pool.go b/core/tx_pool.go index 1acd488..5b2a3c0 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -528,7 +528,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Ensure the transaction doesn't exceed the current block limit gas. if pool.currentMaxGas < tx.Gas() { - fmt.Println(pool.currentMaxGas, tx.Gas()) return ErrGasLimit } // Make sure the transaction is signed properly diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index 0410632..dd0d069 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -21,6 +21,8 @@ func (t txdata) MarshalJSON() ([]byte, error) { GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` + CoinID *common.Hash `json:"coinid" rlp:"nil"` + Amount2 *hexutil.Big `json:"value2" rlp:"nil"` Payload hexutil.Bytes `json:"input" gencodec:"required"` V *hexutil.Big `json:"v" gencodec:"required"` R *hexutil.Big `json:"r" gencodec:"required"` @@ -33,6 +35,8 @@ func (t txdata) MarshalJSON() ([]byte, error) { enc.GasLimit = hexutil.Uint64(t.GasLimit) enc.Recipient = t.Recipient enc.Amount = (*hexutil.Big)(t.Amount) + enc.CoinID = t.CoinID + enc.Amount2 = (*hexutil.Big)(t.Amount2) enc.Payload = t.Payload enc.V = (*hexutil.Big)(t.V) enc.R = (*hexutil.Big)(t.R) @@ -49,6 +53,8 @@ func (t *txdata) UnmarshalJSON(input []byte) error { GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` + CoinID *common.Hash `json:"coinid" rlp:"nil"` + Amount2 *hexutil.Big `json:"value2" rlp:"nil"` Payload *hexutil.Bytes `json:"input" gencodec:"required"` V *hexutil.Big `json:"v" gencodec:"required"` R *hexutil.Big `json:"r" gencodec:"required"` @@ -78,6 +84,12 @@ func (t *txdata) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'value' for txdata") } t.Amount = (*big.Int)(dec.Amount) + if dec.CoinID != nil { + t.CoinID = dec.CoinID + } + if dec.Amount2 != nil { + t.Amount2 = (*big.Int)(dec.Amount2) + } if dec.Payload == nil { return errors.New("missing required field 'input' for txdata") } diff --git a/core/types/transaction.go b/core/types/transaction.go index cf9e61a..858b443 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -49,8 +49,8 @@ type txdata struct { GasLimit uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation Amount *big.Int `json:"value" gencodec:"required"` - CoinID *common.Hash `json:"coinid" rlp:"-"` - Amount2 *big.Int `json:"value2"` + CoinID *common.Hash `json:"coinid" rlp:"nil"` + Amount2 *big.Int `json:"value2" rlp:"nil"` Payload []byte `json:"input" gencodec:"required"` // Signature values @@ -67,7 +67,7 @@ type txdataMarshaling struct { Price *hexutil.Big GasLimit hexutil.Uint64 Amount *hexutil.Big - CoinID *hexutil.Bytes + CoinID *common.Hash Amount2 *hexutil.Big Payload hexutil.Bytes V *hexutil.Big @@ -183,14 +183,14 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return nil } -func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } -func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } -func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } -func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } -func (tx *Transaction) CoinID() *big.Int { return big.NewInt(0) } -func (tx *Transaction) Value2() *big.Int { return big.NewInt(0) } -func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } -func (tx *Transaction) CheckNonce() bool { return true } +func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } +func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } +func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } +func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } +func (tx *Transaction) CoinID() *common.Hash { return tx.data.CoinID } +func (tx *Transaction) Value2() *big.Int { return new(big.Int).Set(tx.data.Amount2) } +func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } +func (tx *Transaction) CheckNonce() bool { return true } // To returns the recipient address of the transaction. // It returns nil if the transaction is a contract creation. diff --git a/core/vm/evm.go b/core/vm/evm.go index ff3587c..be8b240 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,7 +17,6 @@ package vm import ( - "fmt" "math/big" "sync/atomic" "time" @@ -260,7 +259,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // This allows the user transfer balance of a specified coinId in addition to a normal Call(). func (evm *EVM) CallExpert(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, coinID *common.Hash, value2 *big.Int) (ret []byte, leftOverGas uint64, err error) { - fmt.Println("CallExpert") if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } diff --git a/eth/backend.go b/eth/backend.go index ab43558..983909c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -173,8 +173,6 @@ func New(ctx *node.ServiceContext, config *Config, bcb: bcb, } - fmt.Println(eth.config.Genesis.GasLimit) - bcVersion := rawdb.ReadDatabaseVersion(chainDb) var dbVer = "" if bcVersion != nil { diff --git a/eth/gen_config.go b/eth/gen_config.go index 617a885..d34f0b3 100644 --- a/eth/gen_config.go +++ b/eth/gen_config.go @@ -49,6 +49,8 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap *big.Int `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideIstanbul *big.Int + ManualCanonical bool } var enc Config enc.Genesis = c.Genesis @@ -82,6 +84,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCGasCap = c.RPCGasCap enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle + enc.OverrideIstanbul = c.OverrideIstanbul + enc.ManualCanonical = c.ManualCanonical return &enc, nil } @@ -119,6 +123,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *big.Int `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideIstanbul *big.Int + ManualCanonical *bool } var dec Config if err := unmarshal(&dec); err != nil { @@ -217,5 +223,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.CheckpointOracle != nil { c.CheckpointOracle = dec.CheckpointOracle } + if dec.OverrideIstanbul != nil { + c.OverrideIstanbul = dec.OverrideIstanbul + } + if dec.ManualCanonical != nil { + c.ManualCanonical = *dec.ManualCanonical + } return nil } diff --git a/eth/tracers/internal/tracers/assets.go b/eth/tracers/internal/tracers/assets.go index d0a0bf7..b1930dc 100644 --- a/eth/tracers/internal/tracers/assets.go +++ b/eth/tracers/internal/tracers/assets.go @@ -3,7 +3,7 @@ // 4byte_tracer.js (2.933kB) // bigram_tracer.js (1.712kB) // call_tracer.js (8.643kB) -// evmdis_tracer.js (4.194kB) +// evmdis_tracer.js (4.195kB) // noop_tracer.js (1.271kB) // opcount_tracer.js (1.372kB) // prestate_tracer.js (4.234kB) @@ -28,7 +28,7 @@ import ( func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) + return nil, fmt.Errorf("read %q: %w", name, err) } var buf bytes.Buffer @@ -36,7 +36,7 @@ func bindataRead(data []byte, name string) ([]byte, error) { clErr := gz.Close() if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) + return nil, fmt.Errorf("read %q: %w", name, err) } if clErr != nil { return nil, err @@ -137,7 +137,7 @@ func call_tracerJs() (*asset, error) { return a, nil } -var _evmdis_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\xdf\x6f\xda\xca\x12\x7e\x86\xbf\x62\x94\x27\x50\x29\x60\x63\x08\x38\x27\x47\xe2\xa6\xf4\x1c\xae\xd2\x24\x02\x72\x8f\x2a\x94\x87\x05\xc6\xb0\xaa\xf1\x5a\xbb\x6b\x72\xb8\x55\xfe\xf7\xab\xd9\x59\x03\xf9\x75\xdb\x4a\xa7\x0f\x3b\xb5\x77\xbe\x6f\xbe\x9d\x19\xcf\x92\x56\x0b\xae\x54\xbe\xd7\x72\xbd\xb1\x10\xb6\x83\x73\x98\x6d\x10\xd6\xea\x23\xda\x0d\x6a\x2c\xb6\x30\x2c\xec\x46\x69\x53\x6d\xb5\x60\xb6\x91\x06\x12\x99\x22\x48\x03\xb9\xd0\x16\x54\x02\xf6\x85\x7f\x2a\x17\x5a\xe8\x7d\xb3\xda\x6a\x31\xe6\xcd\x6d\x62\x48\x34\x22\x18\x95\xd8\x47\xa1\x31\x86\xbd\x2a\x60\x29\x32\xd0\xb8\x92\xc6\x6a\xb9\x28\x2c\x82\xb4\x20\xb2\x55\x4b\x69\xd8\xaa\x95\x4c\xf6\x44\x29\x2d\x14\xd9\x0a\xb5\x0b\x6d\x51\x6f\x4d\xa9\xe3\x8f\x9b\x7b\xb8\x46\x63\x50\xc3\x1f\x98\xa1\x16\x29\xdc\x15\x8b\x54\x2e\xe1\x5a\x2e\x31\x33\x08\xc2\x40\x4e\x6f\xcc\x06\x57\xb0\x70\x74\x04\xfc\x4c\x52\xa6\x5e\x0a\x7c\x56\x45\xb6\x12\x56\xaa\xac\x01\x28\x49\x39\xec\x50\x1b\xa9\x32\xe8\x94\xa1\x3c\x61\x03\x94\x26\x92\x9a\xb0\x74\x00\x0d\x2a\x27\x5c\x1d\x44\xb6\x87\x54\xd8\x23\xf4\x27\x12\x72\x3c\xf7\x0a\x64\xe6\xc2\x6c\x54\x8e\x60\x37\xc2\xd2\xa9\x1f\x65\x9a\xc2\x02\xa1\x30\x98\x14\x69\x83\xd8\x16\x85\x85\xbf\xc6\xb3\x3f\x6f\xef\x67\x30\xbc\xf9\x0a\x7f\x0d\x27\x93\xe1\xcd\xec\xeb\x05\x3c\x4a\xbb\x51\x85\x05\xdc\x21\x53\xc9\x6d\x9e\x4a\x5c\xc1\xa3\xd0\x5a\x64\x76\x0f\x2a\x21\x86\x2f\xa3\xc9\xd5\x9f\xc3\x9b\xd9\xf0\x5f\xe3\xeb\xf1\xec\x2b\x28\x0d\x9f\xc7\xb3\x9b\xd1\x74\x0a\x9f\x6f\x27\x30\x84\xbb\xe1\x64\x36\xbe\xba\xbf\x1e\x4e\xe0\xee\x7e\x72\x77\x3b\x1d\x35\x61\x8a\xa4\x0a\x09\xff\xe3\x9c\x27\xae\x7a\x1a\x61\x85\x56\xc8\xd4\x94\x99\xf8\xaa\x0a\x30\x1b\x55\xa4\x2b\xd8\x88\x1d\x82\xc6\x25\xca\x1d\xae\x40\xc0\x52\xe5\xfb\x9f\x2e\x2a\x71\x89\x54\x65\x6b\x77\xe6\x77\x1b\x12\xc6\x09\x64\xca\x36\xc0\x20\xc2\x6f\x1b\x6b\xf3\xb8\xd5\x7a\x7c\x7c\x6c\xae\xb3\xa2\xa9\xf4\xba\x95\x32\x9d\x69\xfd\xde\xac\x12\x27\xee\xb6\x2b\x69\x66\x5a\x2c\x51\x83\x46\x5b\xe8\xcc\x80\x29\x92\x84\xfc\x2c\xc8\x2c\x51\x7a\xeb\xda\x04\x12\xad\xb6\x20\xc0\x92\x2f\x58\x05\x39\x6a\xda\xf4\x14\x1f\x8d\xdd\xa7\x4e\xe6\x4a\x1a\x61\x0c\x6e\x17\xe9\xbe\x59\xfd\x5e\xad\x18\x2b\x96\xdf\x62\x98\x7f\x57\xb9\x89\x61\xfe\xf0\xf4\xd0\xa8\x56\x2b\x59\x5e\x98\x0d\x9a\x18\xbe\xb7\x63\x68\x37\x20\x88\x21\x68\x40\xe8\xd6\x8e\x5b\x23\xb7\x76\xdd\xda\x73\xeb\xb9\x5b\xfb\x6e\x1d\xb8\x35\x68\xb3\x61\x74\xc0\x6e\x01\xfb\x05\xec\x18\xb0\x67\xc8\x9e\xa1\x8f\xc3\x81\x42\x8e\x14\x72\xa8\x90\x63\x85\xcc\xd2\x61\x97\x88\x59\x22\x66\xe9\x32\x4b\x97\x59\xba\xec\xd2\x65\x96\xae\x17\xdc\x75\xe7\xe9\x32\x4b\xf7\x9c\x9f\x98\xa5\xcb\x2c\x3d\x3e\x72\x8f\x01\x3d\x7f\x44\x06\xf4\x58\x7c\x8f\x01\x3d\x06\xf4\x19\xd0\xe7\xb0\xfd\x90\x9f\x3a\x6c\x98\xa5\xcf\x61\xfb\x3d\x36\x1c\xb6\xcf\x2c\x7d\x66\x19\xb0\xf8\x41\xe0\xf6\x06\x1c\x6f\xc0\xf1\x06\x3e\xab\x65\x5a\x7d\x5e\xdb\x3e\xb1\xed\xd0\xdb\x8e\xb7\x91\xb7\x5d\x6f\x7d\xe6\xdb\x3e\xf5\x6d\x9f\xfb\xb6\xe7\x3b\xd4\xc9\xf3\x05\x9e\x2f\xf0\x7c\x81\xe7\x0b\x3c\x5f\x59\xc9\xb2\x94\x65\x2d\x7d\x31\x03\x5f\xcd\xc0\x97\x33\xf0\xf5\x0c\x7c\x41\x03\x5f\xd1\xc0\x97\x34\xf0\x35\x0d\x42\xcf\x17\xf6\x63\x08\xc9\x0e\x62\xe8\x34\x20\xe8\xb4\x63\x88\xc8\x06\x31\x74\xc9\x86\x31\xf4\xc8\x76\x62\x38\x27\x1b\xc5\xd0\x27\xdb\x8d\x61\x40\x96\xf8\xa8\x6b\x3b\x44\x48\x8c\x1d\x52\x48\x94\x1d\x92\x48\x9c\x11\x69\x24\xd2\x88\x44\x12\x6b\x44\x2a\x89\x36\x22\x99\xc4\x1b\x45\xac\x23\xea\xb2\x8e\xa8\xc7\x3a\xa2\x73\xd6\x41\xdd\xe7\x00\x03\xd6\x41\xfd\x47\x3a\xa8\x01\x49\x87\xeb\x40\xd2\xe1\x7a\x90\x74\xb8\x2e\x24\x4a\xea\x43\xa7\xc3\x75\x22\x91\x52\x2f\x3a\x1d\xae\x1b\x89\xd6\xf5\x23\xf1\xfa\x8e\x0c\x7a\x81\xb7\xa1\xb7\x1d\x6f\x23\x67\xc3\xc8\x7f\x45\x91\xff\x8c\x22\xff\x1d\x45\x1d\xbf\xef\xfd\xdc\x47\xf0\x44\xdf\x79\xab\x05\x1a\x4d\x91\x5a\x1a\xfe\x32\xdb\xa9\x6f\x34\x9e\x37\x98\x81\x48\x53\x37\xc7\x54\xbe\x54\x2b\x34\x3c\x1f\x17\x88\x19\x48\x8b\x5a\xd0\x05\xa1\x76\xa8\xe9\x6e\x2c\x27\x93\xa3\x23\x4c\x22\x33\x91\x96\xc4\x7e\x86\xd2\x60\x92\xd9\xba\x59\xad\xf0\xfb\x18\x92\x22\x5b\xd2\xe8\xaa\xd5\xe1\xbb\xa7\x00\xbb\x91\xa6\xe9\x46\xd2\xbc\xfd\xd0\x54\xb9\xb9\x80\x52\x67\x22\xde\x92\x49\xd4\x62\x69\x0b\x91\x02\xfe\x8d\xcb\xc2\xcd\x42\x95\x80\xc8\xbc\x72\x48\x78\xe0\x57\x1c\xfe\x24\x6a\xaa\xd6\x0d\x58\x2d\x28\x78\x19\xc2\x58\xcc\x4f\x23\xd0\xb5\x81\x3b\xd4\xfb\x92\xcb\x5d\x83\x14\xf2\x3f\x5f\x7c\x38\x24\x6a\xc2\xbd\xc9\x5c\xad\x54\x76\x42\x43\xa2\xc5\x16\xe1\xf2\xf4\x74\xc7\xff\x36\x53\xcc\xd6\x76\x03\x1f\x21\x78\xb8\xa8\x7a\x04\x6a\xad\x34\x5c\x42\xaa\xd6\xcd\x35\xda\x11\x3d\xd6\xea\x17\xd5\x4a\x45\x26\x50\x73\xbb\x4c\x5f\x71\xdc\xf3\x33\xf7\xea\xec\x01\x2e\x19\x4a\x9e\x4f\x80\xa9\x41\x20\x80\xa7\xf9\x84\xb9\xdd\xd4\xea\x70\x79\x2a\xc5\xc7\xf7\x74\x2a\xa7\x4b\x05\x2e\xf9\xa9\xa2\xf2\x18\xe8\x1f\x11\xa8\xbc\x69\xd5\x4d\xb1\x5d\xa0\xae\xd5\x1b\x6e\x7b\x45\x84\x10\xc3\x73\x7e\xde\x2b\xcb\x3c\x7f\x70\xcf\x4f\x24\xc9\xa9\x77\x8a\xa9\xb6\xe5\xc9\x7f\x87\xb6\x8f\xee\xce\x9e\x6b\xdc\xa9\x1c\x2e\xe1\xe0\x38\x7f\x05\xe1\x64\x11\x22\x51\xba\x46\x28\x09\x97\xd0\xbe\x00\x09\xbf\xf1\xd9\xfc\x0d\x36\x67\xb6\xa6\xca\x1f\x2e\x40\x7e\xf8\x50\x77\xa0\x8a\x7f\xcb\x1a\x9b\xe4\xea\x72\xc4\x09\xc9\x11\xbf\xd5\x64\xbd\x69\xd5\xd4\x6a\x99\xad\x6b\x41\xaf\xee\x72\x5f\x79\xa2\xc5\x3c\x4a\xbb\x64\x7f\x97\x12\xef\x54\xf7\x67\x58\x0a\x83\x70\x76\x35\xbc\xbe\x3e\x8b\xe1\xf8\x70\x75\xfb\x69\x74\x16\x1f\x0e\x29\x33\x63\xe9\xe7\x2b\x97\xf8\x24\x6e\xa7\xde\xdc\x89\xb4\xc0\xdb\x84\xeb\x7d\x70\x97\xff\xc5\xd7\xde\xd1\x2b\x6f\x2e\xe0\xfc\x6c\x2d\x8c\x6b\x87\x17\x80\xf6\xbb\x00\xab\xde\xf2\x0f\x9e\xa7\xe1\x39\xc4\x31\xbd\x85\x0a\x4f\x50\x2f\x30\x32\xcb\x0b\x7b\xc0\x6c\x71\xab\xf4\xbe\x69\xe8\x87\x4f\xcd\xe7\xa4\x71\x48\xce\x07\x7f\xee\x17\x14\xc7\x5e\xcf\x8a\x34\x7d\xbe\xc7\x73\xe4\x9d\x4d\x95\x73\x4e\xe6\xbe\x77\x4e\x3e\x02\xd7\x02\xec\xe7\xa3\x2d\x34\x8a\x6f\x17\xc7\x8a\x7e\x1a\x5d\x8f\xfe\x18\xce\x46\xcf\x2a\x3b\x9d\x0d\x67\xe3\x2b\x7e\xf5\xe3\xda\x86\xbf\x54\xdb\xd7\x9d\x70\x3c\x87\x3b\x06\xbc\x6a\xc1\xb7\x5b\xe0\x97\x7b\xe0\x97\x9a\xe0\x58\xd0\x7f\xa2\xa2\xff\xbf\xa4\xff\x74\x4d\x27\xa3\xd9\xfd\xe4\xe6\xa4\x74\xf4\xe7\xca\x4f\x7c\x33\xde\xf5\xed\xba\x05\xaf\xdc\x79\x7c\xf9\x2b\xee\x8d\xc6\x57\x85\x6d\xb8\xd0\x1f\x4a\xd6\x77\xf4\x4e\x67\xb7\x77\xc7\xde\xbb\x1f\x5f\x8d\x0f\x43\xe5\x47\x31\xda\x0d\x68\xbf\xc3\xfa\xef\xfb\x2f\x77\x9f\x46\xd3\x99\x67\x2a\x33\x9b\x2f\x0f\x9f\xe9\x1a\xed\xdd\x55\xed\x64\x06\xca\xa4\x9c\x7f\xd2\xdc\x51\x9a\xcb\xe9\x77\x40\xa7\x98\x1d\xe0\xcf\x6e\x0e\xf8\x08\xed\xbf\xbb\x78\xe4\x3a\x0e\xf7\x97\x05\xf3\x37\x98\x23\x3e\xd6\xf5\xd9\x45\x7a\x3c\xdd\xf3\x3b\x88\xf1\xd5\xca\x53\xf5\xa9\xfa\xbf\x00\x00\x00\xff\xff\x51\x4b\xdc\x7e\x62\x10\x00\x00") +var _evmdis_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\xdf\x6f\xda\xca\x12\x7e\x86\xbf\x62\x94\x27\x50\x29\x60\x63\x08\x38\x27\x47\xe2\xa6\xf4\x1c\xae\xd2\x24\x02\x72\x8f\x2a\x94\x87\x05\xc6\xb0\xaa\xf1\x5a\xbb\x6b\x72\xb8\x55\xfe\xf7\xab\xd9\x59\x03\xf9\x75\xdb\x4a\xa7\x0f\x3b\xb5\x77\xbe\x6f\xbe\x9d\x19\xcf\x92\x56\x0b\xae\x54\xbe\xd7\x72\xbd\xb1\x10\xb6\x83\x73\x98\x6d\x10\xd6\xea\x23\xda\x0d\x6a\x2c\xb6\x30\x2c\xec\x46\x69\x53\x6d\xb5\x60\xb6\x91\x06\x12\x99\x22\x48\x03\xb9\xd0\x16\x54\x02\xf6\x85\x7f\x2a\x17\x5a\xe8\x7d\xb3\xda\x6a\x31\xe6\xcd\x6d\x62\x48\x34\x22\x18\x95\xd8\x47\xa1\x31\x86\xbd\x2a\x60\x29\x32\xd0\xb8\x92\xc6\x6a\xb9\x28\x2c\x82\xb4\x20\xb2\x55\x4b\x69\xd8\xaa\x95\x4c\xf6\x44\x29\x2d\x14\xd9\x0a\xb5\x0b\x6d\x51\x6f\x4d\xa9\xe3\x8f\x9b\x7b\xb8\x46\x63\x50\xc3\x1f\x98\xa1\x16\x29\xdc\x15\x8b\x54\x2e\xe1\x5a\x2e\x31\x33\x08\xc2\x40\x4e\x6f\xcc\x06\x57\xb0\x70\x74\x04\xfc\x4c\x52\xa6\x5e\x0a\x7c\x56\x45\xb6\x12\x56\xaa\xac\x01\x28\x49\x39\xec\x50\x1b\xa9\x32\xe8\x94\xa1\x3c\x61\x03\x94\x26\x92\x9a\xb0\x74\x00\x0d\x2a\x27\x5c\x1d\x44\xb6\x87\x54\xd8\x23\xf4\x27\x12\x72\x3c\xf7\x0a\x64\xe6\xc2\x6c\x54\x8e\x60\x37\xc2\xd2\xa9\x1f\x65\x9a\xc2\x02\xa1\x30\x98\x14\x69\x83\xd8\x16\x85\x85\xbf\xc6\xb3\x3f\x6f\xef\x67\x30\xbc\xf9\x0a\x7f\x0d\x27\x93\xe1\xcd\xec\xeb\x05\x3c\x4a\xbb\x51\x85\x05\xdc\x21\x53\xc9\x6d\x9e\x4a\x5c\xc1\xa3\xd0\x5a\x64\x76\x0f\x2a\x21\x86\x2f\xa3\xc9\xd5\x9f\xc3\x9b\xd9\xf0\x5f\xe3\xeb\xf1\xec\x2b\x28\x0d\x9f\xc7\xb3\x9b\xd1\x74\x0a\x9f\x6f\x27\x30\x84\xbb\xe1\x64\x36\xbe\xba\xbf\x1e\x4e\xe0\xee\x7e\x72\x77\x3b\x1d\x35\x61\x8a\xa4\x0a\x09\xff\xe3\x9c\x27\xae\x7a\x1a\x61\x85\x56\xc8\xd4\x94\x99\xf8\xaa\x0a\x30\x1b\x55\xa4\x2b\xd8\x88\x1d\x82\xc6\x25\xca\x1d\xae\x40\xc0\x52\xe5\xfb\x9f\x2e\x2a\x71\x89\x54\x65\x6b\x77\xe6\x77\x1b\x12\xc6\x09\x64\xca\x36\xc0\x20\xc2\x6f\x1b\x6b\xf3\xb8\xd5\x7a\x7c\x7c\x6c\xae\xb3\xa2\xa9\xf4\xba\x95\x32\x9d\x69\xfd\xde\xac\x12\x27\xee\xb6\x2b\x69\x66\x5a\x2c\x51\x83\x46\x5b\xe8\xcc\x80\x29\x92\x44\x2e\x25\x66\x16\x64\x96\x28\xbd\x75\x7d\x02\x89\x56\x5b\x10\x60\xc9\x19\xac\x82\x1c\x35\x6d\x7a\x8e\x8f\xc6\xee\x53\xa7\x73\x25\x8d\x30\x06\xb7\x8b\x74\xdf\xac\x7e\xaf\x56\x8c\x15\xcb\x6f\x31\xcc\xbf\xab\xdc\xc4\x30\x7f\x78\x7a\x68\x54\xab\x95\x2c\x2f\xcc\x06\x4d\x0c\xdf\xdb\x31\xb4\x1b\x10\xc4\x10\x34\x20\x74\x6b\xc7\xad\x91\x5b\xbb\x6e\xed\xb9\xf5\xdc\xad\x7d\xb7\x0e\xdc\x1a\xb4\xd9\x30\x3a\x60\xb7\x80\xfd\x02\x76\x0c\xd8\x33\x64\xcf\xd0\xc7\xe1\x40\x21\x47\x0a\x39\x54\xc8\xb1\x42\x66\xe9\xb0\x4b\xc4\x2c\x11\xb3\x74\x99\xa5\xcb\x2c\x5d\x76\xe9\x32\x4b\xd7\x0b\xee\xba\xf3\x74\x99\xa5\x7b\xce\x4f\xcc\xd2\x65\x96\x1e\x1f\xb9\xc7\x80\x9e\x3f\x22\x03\x7a\x2c\xbe\xc7\x80\x1e\x03\xfa\x0c\xe8\x73\xd8\x7e\xc8\x4f\x1d\x36\xcc\xd2\xe7\xb0\xfd\x1e\x1b\x0e\xdb\x67\x96\x3e\xb3\x0c\x58\xfc\x20\x70\x7b\x03\x8e\x37\xe0\x78\x03\x9f\xd5\x32\xad\x3e\xaf\x6d\x9f\xd8\x76\xe8\x6d\xc7\xdb\xc8\xdb\xae\xb7\x3e\xf3\x6d\x9f\xfa\xb6\xcf\x7d\xdb\xf3\x1d\xea\xe4\xf9\x02\xcf\x17\x78\xbe\xc0\xf3\x05\x9e\xaf\xac\x64\x59\xca\xb2\x96\xbe\x98\x81\xaf\x66\xe0\xcb\x19\xf8\x7a\x06\xbe\xa0\x81\xaf\x68\xe0\x4b\x1a\xf8\x9a\x06\xa1\xe7\x0b\xfb\x31\x84\x64\x07\x31\x74\x1a\x10\x74\xda\x31\x44\x64\x83\x18\xba\x64\xc3\x18\x7a\x64\x3b\x31\x9c\x93\x8d\x62\xe8\x93\xed\xc6\x30\x20\x4b\x7c\xd4\xb5\x1d\x22\x24\xc6\x0e\x29\x24\xca\x0e\x49\x24\xce\x88\x34\x12\x69\x44\x22\x89\x35\x22\x95\x44\x1b\x91\x4c\xe2\x8d\x22\xd6\x11\x75\x59\x47\xd4\x63\x1d\xd1\x39\xeb\xa0\xee\x73\x80\x01\xeb\xa0\xfe\x23\x1d\xd4\x80\xa4\xc3\x75\x20\xe9\x70\x3d\x48\x3a\x5c\x17\x12\x25\xf5\xa1\xd3\xe1\x3a\x91\x48\xa9\x17\x9d\x0e\xd7\x8d\x44\xeb\xfa\x91\x78\x7d\x47\x06\xbd\xc0\xdb\xd0\xdb\x8e\xb7\x91\xb3\x61\xe4\xbf\xa2\xc8\x7f\x46\x91\xff\x8e\xa2\x8e\xdf\xf7\x7e\xee\x23\x78\xa2\xef\xbc\xd5\x02\x8d\xa6\x48\x2d\x4d\x7f\x99\xed\xd4\x37\x9a\xcf\x1b\xcc\x40\xa4\xa9\x1b\x64\x2a\x5f\xaa\x15\x1a\x1e\x90\x0b\xc4\x0c\xa4\x45\x2d\xe8\x86\x50\x3b\xd4\x74\x39\x96\xa3\xc9\xd1\x11\x26\x91\x99\x48\x4b\x62\x3f\x44\x69\x30\xc9\x6c\xdd\xac\x56\xf8\x7d\x0c\x49\x91\x2d\x69\x74\xd5\xea\xf0\xdd\x53\x80\xdd\x48\xd3\x74\x23\x69\xde\x7e\x68\xaa\xdc\x5c\x40\xa9\x33\x11\x6f\xc9\x24\x6a\xb1\xb4\x85\x48\x01\xff\xc6\x65\xe1\x66\xa1\x4a\x40\x64\x5e\x39\x24\x3c\xf1\x2b\x0e\x7f\x12\x35\x55\xeb\x06\xac\x16\x14\xbc\x0c\x61\x2c\xe6\xa7\x11\xe8\xde\xc0\x1d\xea\x7d\xc9\xe5\xee\x41\x0a\xf9\x9f\x2f\x3e\x1c\x12\x35\xe1\xde\x64\xae\x56\x2a\x3b\xa1\x21\xd1\x62\x8b\x70\x79\x7a\xba\xe3\x7f\x9b\x29\x66\x6b\xbb\x81\x8f\x10\x3c\x5c\x54\x3d\x02\xb5\x56\x1a\x2e\x21\x55\xeb\xe6\x1a\xed\x88\x1e\x6b\xf5\x8b\x6a\xa5\x22\x13\xa8\xb9\x5d\xa6\xaf\x38\xee\xf9\x99\x7b\x75\xf6\x00\x97\x0c\x25\xcf\x27\xc0\xd4\x20\x10\xc0\xd3\x7c\xc2\xdc\x6e\x6a\x75\xb8\x3c\x95\xe2\xe3\x7b\x3a\x95\xd3\xa5\x02\x97\xfc\x54\x51\x79\x0c\xf4\x8f\x08\x54\xde\xb4\xea\xa6\xd8\x2e\x50\xd7\xea\x0d\xb7\xbd\x22\x42\x88\xe1\x39\x3f\xef\x95\x65\x9e\x3f\xb8\xe7\x27\x92\xe4\xd4\x3b\xc5\x54\xdb\xf2\xe4\xbf\x43\xdb\x47\x77\x67\xcf\x35\xee\x54\x0e\x97\x70\x70\x9c\xbf\x82\x70\xb2\x08\x91\x28\x5d\x23\x94\x84\x4b\x68\x5f\x80\x84\xdf\xf8\x6c\xfe\x06\x9b\x33\x5b\x53\xe5\x0f\x17\x20\x3f\x7c\xa8\x3b\x50\xc5\xbf\x65\x8d\x4d\x72\x75\x39\xe2\x84\xe4\x88\xdf\x6a\xb2\xde\xb4\x6a\x6a\xb5\xcc\xd6\xb5\xa0\x57\x77\xb9\xaf\x3c\xd1\x62\x1e\xa5\x5d\xb2\xbf\x4b\x89\x77\xaa\xfb\x33\x2c\x85\x41\x38\xbb\x1a\x5e\x5f\x9f\xc5\x70\x7c\xb8\xba\xfd\x34\x3a\x8b\x0f\x87\x94\x99\xb1\xf4\xfb\x95\x4b\x7c\x12\xb7\x53\x6f\xee\x44\x5a\xe0\x6d\xc2\xf5\x3e\xb8\xcb\xff\xe2\x6b\xef\xe8\x95\x37\x17\x70\x7e\xb6\x16\xc6\xb5\xc3\x0b\x40\xfb\x5d\x80\x55\x6f\xf9\x07\xcf\xd3\xf0\x1c\xe2\x98\xde\x42\x85\x27\xa8\x17\x18\x99\xe5\x85\x3d\x60\xb6\xb8\x55\x7a\xdf\x34\xf4\xcb\xa7\xe6\x73\xd2\x38\x24\xe7\x83\x3f\xf7\x0b\x8a\x63\xaf\x67\x45\x9a\x3e\xdf\xe3\x39\xf2\xce\xa6\xca\x39\x27\x73\xdf\x3b\x27\x1f\x81\x6b\x01\xf6\xf3\xd1\x16\x1a\xc5\xb7\x8b\x63\x45\x3f\x8d\xae\x47\x7f\x0c\x67\xa3\x67\x95\x9d\xce\x86\xb3\xf1\x15\xbf\xfa\x71\x6d\xc3\x5f\xaa\xed\xeb\x4e\x38\x9e\xc3\x1d\x03\x5e\xb5\xe0\xdb\x2d\xf0\xcb\x3d\xf0\x4b\x4d\x70\x2c\xe8\x3f\x51\xd1\xff\x5f\xd2\x7f\xba\xa6\x93\xd1\xec\x7e\x72\x73\x52\x3a\xfa\x7b\xe5\x27\xbe\x19\xef\xfa\x76\xdd\x82\x57\xee\x3c\xbe\xfc\x15\xf7\x46\xe3\xab\xc2\x36\x5c\xe8\x0f\x25\xeb\x3b\x7a\xa7\xb3\xdb\xbb\x63\xef\xdd\x8f\xaf\xc6\x87\xa1\xf2\xa3\x18\xed\x06\xb4\xdf\x61\xfd\xf7\xfd\x97\xbb\x4f\xa3\xe9\xcc\x33\x95\x99\xcd\x97\x87\xcf\x74\x8d\xf6\xee\xaa\x76\x32\x03\x65\x52\xce\x3f\x69\xee\x28\xcd\xe5\xf4\x3b\xa0\x53\xcc\x0e\xf0\x67\x37\x07\x7c\x84\xf6\xdf\x5d\x3c\x72\x1d\x87\xfb\xcb\x82\xf9\x1b\xcc\x11\x1f\xeb\xfa\xec\x22\x3d\x9e\xee\xf9\x1d\xc4\xf8\x6a\xe5\xa9\xfa\x54\xfd\x5f\x00\x00\x00\xff\xff\xdf\x2f\xd9\xfa\x63\x10\x00\x00") func evmdis_tracerJsBytes() ([]byte, error) { return bindataRead( @@ -153,7 +153,7 @@ func evmdis_tracerJs() (*asset, error) { } info := bindataFileInfo{name: "evmdis_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd5, 0xe8, 0x96, 0xa1, 0x8b, 0xc, 0x68, 0x3c, 0xe8, 0x5d, 0x7e, 0xf0, 0xab, 0xfe, 0xec, 0xd1, 0xb, 0x3d, 0xfc, 0xc7, 0xac, 0xb5, 0xa, 0x41, 0x55, 0x0, 0x3a, 0x60, 0xa7, 0x8e, 0x46, 0x93}} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb5, 0xc8, 0x73, 0x8e, 0xfb, 0x1f, 0x84, 0x7d, 0x37, 0xd9, 0x26, 0x24, 0x37, 0xb8, 0x65, 0xb1, 0xed, 0xa0, 0x76, 0x9a, 0xf0, 0x8e, 0x3a, 0x9b, 0x20, 0x93, 0x27, 0x26, 0x2e, 0xc9, 0x9b, 0xde}} return a, nil } @@ -348,25 +348,20 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - "4byte_tracer.js": _4byte_tracerJs, - - "bigram_tracer.js": bigram_tracerJs, - - "call_tracer.js": call_tracerJs, - - "evmdis_tracer.js": evmdis_tracerJs, - - "noop_tracer.js": noop_tracerJs, - - "opcount_tracer.js": opcount_tracerJs, - + "4byte_tracer.js": _4byte_tracerJs, + "bigram_tracer.js": bigram_tracerJs, + "call_tracer.js": call_tracerJs, + "evmdis_tracer.js": evmdis_tracerJs, + "noop_tracer.js": noop_tracerJs, + "opcount_tracer.js": opcount_tracerJs, "prestate_tracer.js": prestate_tracerJs, - - "trigram_tracer.js": trigram_tracerJs, - - "unigram_tracer.js": unigram_tracerJs, + "trigram_tracer.js": trigram_tracerJs, + "unigram_tracer.js": unigram_tracerJs, } +// AssetDebug is true if the assets were built with the debug flag enabled. +const AssetDebug = false + // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the diff --git a/examples/chain/main.go b/examples/chain/main.go index d474c2b..5edd055 100644 --- a/examples/chain/main.go +++ b/examples/chain/main.go @@ -7,10 +7,10 @@ import ( "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/eth" + "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/hexutil" "github.com/ava-labs/go-ethereum/log" - "github.com/ava-labs/go-ethereum/params" "github.com/ava-labs/go-ethereum/rlp" "math/big" "sync" diff --git a/examples/counter/main.go b/examples/counter/main.go index 48a0e6f..85aa9d1 100644 --- a/examples/counter/main.go +++ b/examples/counter/main.go @@ -9,11 +9,11 @@ import ( "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/eth" + "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/compiler" "github.com/ava-labs/go-ethereum/crypto" "github.com/ava-labs/go-ethereum/log" - "github.com/ava-labs/go-ethereum/params" "go/build" "math/big" "os" diff --git a/examples/multicoin/main.go b/examples/multicoin/main.go new file mode 100644 index 0000000..3e42010 --- /dev/null +++ b/examples/multicoin/main.go @@ -0,0 +1,218 @@ +package main + +import ( + "crypto/rand" + //"encoding/hex" + "encoding/json" + "fmt" + "github.com/ava-labs/coreth" + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/eth" + //"github.com/ava-labs/coreth/accounts/abi" + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/compiler" + "github.com/ava-labs/go-ethereum/crypto" + "github.com/ava-labs/go-ethereum/log" + "go/build" + "math/big" + "os" + "os/signal" + "path/filepath" + //"strings" + "syscall" + "time" +) + +var ( + codeHex = "6101c7610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003373ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea26469706673582212204e4689067358d8e82903012dcaca0c004d36e39fc99360919fb824c4ce718bdd64736f6c634300060a0033" + codeABI = `[{"inputs":[{"internalType":"uint256","name":"coinid","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` +) + +func checkError(err error) { + if err != nil { + panic(err) + } +} + +func main() { + // configure the chain + config := eth.DefaultConfig + config.ManualCanonical = true + chainConfig := ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: nil, + Ethash: nil, + } + + // configure the genesis block + //genBalance := big.NewInt(100000000000000000) + genKey, _ := coreth.NewKey(rand.Reader) + bob, _ := coreth.NewKey(rand.Reader) + + g := new(core.Genesis) + b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` + k := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" + err := json.Unmarshal([]byte(b), g) + checkError(err) + config.Genesis = g + hk, _ := crypto.HexToECDSA(k[2:]) + genKey = coreth.NewKeyFromECDSA(hk) + //config.Genesis = &core.Genesis{ + // Config: chainConfig, + // Nonce: 0, + // Number: 0, + // ExtraData: hexutil.MustDecode("0x00"), + // GasLimit: 100000000, + // Difficulty: big.NewInt(0), + // Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}}, + //} + + // grab the control of block generation and disable auto uncle + config.Miner.ManualMining = true + config.Miner.ManualUncle = true + + // compile the smart contract + gopath := os.Getenv("GOPATH") + if gopath == "" { + gopath = build.Default.GOPATH + } + + // info required to generate a transaction + chainID := chainConfig.ChainID + nonce := uint64(0) + gasLimit := 10000000 + gasPrice := big.NewInt(1000000000) + + blockCount := 0 + chain := coreth.NewETHChain(&config, nil, nil, nil) + newTxPoolHeadChan := make(chan core.NewTxPoolHeadEvent, 1) + log.Info(chain.GetGenesisBlock().Hash().Hex()) + firstBlock := false + var contractAddr common.Address + coin0 := common.HexToHash("0x0") + //var calls [][]byte + postGen := func(block *types.Block) bool { + if blockCount == 15 { + state, err := chain.CurrentState() + checkError(err) + log.Info(fmt.Sprintf("genesis balance = %s", state.GetBalance(genKey.Address))) + log.Info(fmt.Sprintf("genesis balance2 = %s", state.GetBalanceMultiCoin(genKey.Address, coin0))) + log.Info(fmt.Sprintf("contract balance = %s", state.GetBalance(contractAddr))) + log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bob.Address))) + log.Info(fmt.Sprintf("bob's balance2 = %s", state.GetBalanceMultiCoin(bob.Address, coin0))) + log.Info(fmt.Sprintf("state = %s", state.Dump(true, false, true))) + log.Info(fmt.Sprintf("x = %s", state.GetState(contractAddr, common.BigToHash(big.NewInt(0))).String())) + return true + } + if !firstBlock { + firstBlock = true + receipts := chain.GetReceiptsByHash(block.Hash()) + if len(receipts) != 1 { + panic(fmt.Sprintf("# receipts is %d != 1", len(receipts))) + } + contractAddr = receipts[0].ContractAddress + txHash := receipts[0].TxHash + log.Info(fmt.Sprintf("deploy tx = %s", txHash.String())) + log.Info(fmt.Sprintf("contract addr = %s", contractAddr.String())) + //var call []byte + //if len(calls) > 0 { + // call = calls[0] + // calls = calls[1:] + //} else { + // call = nil + //} + //state, _ := chain.CurrentState() + //call := common.Hex2Bytes("1003e2d20000000000000000000000000000000000000000000000000000000000000001") + //log.Info(fmt.Sprintf("code = %s", hex.EncodeToString(state.GetCode(contractAddr)))) + go func() { + tx := types.NewTransaction(nonce, bob.Address, big.NewInt(300000000000000000), uint64(gasLimit), gasPrice, nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) + checkError(err) + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + nonce++ + time.Sleep(20 * time.Millisecond) + + // self-loop tx to enable MC + tx = types.NewTransaction(0, bob.Address, big.NewInt(1), uint64(gasLimit), gasPrice, nil) + tx.SetMultiCoinValue(&coin0, big.NewInt(0)) + signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), bob.PrivateKey) + checkError(err) + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + time.Sleep(20 * time.Millisecond) + + for i := 0; i < 10; i++ { + tx := types.NewTransaction(nonce, bob.Address, big.NewInt(10000000000000000), uint64(gasLimit), gasPrice, nil) + tx.SetMultiCoinValue(&coin0, big.NewInt(100000000000000000)) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) + checkError(err) + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + nonce++ + } + }() + } + return false + } + chain.SetOnHeaderNew(func(header *types.Header) { + hid := make([]byte, 32) + _, err := rand.Read(hid) + if err != nil { + panic("cannot generate hid") + } + header.Extra = append(header.Extra, hid...) + }) + chain.SetOnSealFinish(func(block *types.Block) error { + blockCount++ + if postGen(block) { + return nil + } + go func() { + <-newTxPoolHeadChan + time.Sleep(10 * time.Millisecond) + chain.GenBlock() + }() + return nil + }) + + // start the chain + chain.GetTxPool().SubscribeNewHeadEvent(newTxPoolHeadChan) + chain.Start() + + //code := common.Hex2Bytes(codeHex) + counterSrc, err := filepath.Abs(gopath + "/src/github.com/ava-labs/coreth/examples/counter/counter.sol") + checkError(err) + contracts, err := compiler.CompileSolidity("", counterSrc) + checkError(err) + contract, _ := contracts[fmt.Sprintf("%s:%s", counterSrc, "Counter")] + code := common.Hex2Bytes(contract.Code[2:]) + + //abi, err := abi.JSON(strings.NewReader(codeABI)) + //cc, err := abi.Pack("getBalance", big.NewInt(0)) + //checkError(err) + //calls = append(calls, cc) + tx := types.NewContractCreation(nonce, big.NewInt(0), uint64(gasLimit), gasPrice, code) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) + checkError(err) + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + time.Sleep(1000 * time.Millisecond) + nonce++ + + chain.GenBlock() + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + signal.Notify(c, os.Interrupt, syscall.SIGINT) + <-c + chain.Stop() +} diff --git a/plugin/evm/static_service_test.go b/plugin/evm/static_service_test.go deleted file mode 100644 index c492798..0000000 --- a/plugin/evm/static_service_test.go +++ /dev/null @@ -1,64 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "math/big" - "testing" - - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/params" - - "github.com/ava-labs/coreth/core" -) - -func TestBuildGenesis(t *testing.T) { - expected := "3wP629bGfSGj9trh1UNBp5qGRGCcma5d8ezLeSmd9hnUJjSMUJesHHoxbZNcVUC9CjH7PEGNA96htNTd1saZCMt1Mf1dZFG7JDhcYNok6RS4TZufejXdxbVVgquohSa7nCCcrXpiVeiRFwzLJAxyQbXzYRhaCRtcDDfCcqfaVdtkFsPbNeQ49pDTbEC5hVkmfopeQ2Zz8tAG5QXKBdbYBCukR3xNHJ4xDxeixmEwPr1odb42yQRYrL7xREKNn2LFoFwAWUjBTsCkf5GPNgY2GvvN9o8wFWXTroW5fp754DhpdxHYxkMTfuE9DGyNWHTyrEbrUHutUdsfitcSHVj5ctFtkN2wGCs3cyv1eRRNvFFMggWTbarjne6AYaeCrJ631qAu3CbrUtrTH5N2E6G2yQKX4sT4Sk3qWPJdsGXuT95iKKcgNn1u5QRHHw9DXXuGPpJjkcKQRGUCuqpXy61iF5RNPEwAwKDa8f2Y25WMmNgWynUuLj8iSAyePj7USPWk54QFUr86ApVzqAdzzdD1qSVScpmudGnGbz9UNXdzHqSot6XLrNTYsgkabiu6TGntFm7qywbCRmtNdBuT9aznGQdUVimjt5QzUz68HXhUxBzTkrz7yXfVGV5JcWxVHQXYS4oc41U5yu83mH3A7WBrZLVq6UyNrvQVbim5nDxeKKbALPxwzVwywjgY5cp39AvzGnY8CX2AtuBNnKmZaAvG8JWAkx3yxjnJrwWhLgpDQYcCvRp2jg1EPBqN8FKJxSPE6eedjDHDJfB57mNzyEtmg22BPnem3eLdiovX8awkhBUHdE7uPrapNSVprnS85u1saW2Kwza3FsS2jAM3LckGW8KdtfPTpHBTRKAUo49zZLuPsyGL5WduedGyAdaM3a2KPoyXuz4UbexTVUWFNypFvvgyoDS8FMxDCNoMMaD7y4yVnoDpSpVFEVZD6EuSGHe9U8Ew57xLPbjhepDx6" - - balance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16) - if !success { - t.Fatal("Failed to initialize balance") - } - - args := core.Genesis{ - Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(43110), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: big.NewInt(0), - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - }, - Nonce: 0, - Timestamp: 0, - ExtraData: []byte{}, - GasLimit: 100000000, - Difficulty: big.NewInt(0), - Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), - Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"), - Alloc: core.GenesisAlloc{ - common.HexToAddress("751a0b96e1042bee789452ecb20253fba40dbe85"): core.GenesisAccount{ - Balance: balance, - }, - }, - Number: 0, - GasUsed: 0, - ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), - } - - ss := StaticService{} - result, err := ss.BuildGenesis(nil, &args) - if err != nil { - t.Fatal(err) - } - - if result.String() != expected { - t.Fatalf("StaticService.BuildGenesis:\nReturned: %s\nExpected: %s", result, expected) - } -} diff --git a/plugin/evm/vm_genesis_parse_test.go b/plugin/evm/vm_genesis_parse_test.go deleted file mode 100644 index 9a113fb..0000000 --- a/plugin/evm/vm_genesis_parse_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "encoding/json" - "testing" - - "github.com/ava-labs/coreth/core" -) - -func TestParseGenesis(t *testing.T) { - genesis := []byte(`{"config":{"chainId":43110,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x33b2e3c9fd0804000000000"}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`) - - genesisBlock := new(core.Genesis) - err := json.Unmarshal(genesis, genesisBlock) - if err != nil { - t.Fatal(err) - } - - marshalledBytes, err := json.Marshal(genesisBlock) - if err != nil { - t.Fatal(err) - } - - secondGenesisBlock := new(core.Genesis) - err = json.Unmarshal(marshalledBytes, secondGenesisBlock) - if err != nil { - t.Fatal(err) - } -} diff --git a/rpc/client_example_test.go b/rpc/client_example_test.go deleted file mode 100644 index 149de2c..0000000 --- a/rpc/client_example_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc_test - -import ( - "context" - "fmt" - "math/big" - "time" - - "github.com/ava-labs/go-ethereum/rpc" -) - -// In this example, our client wishes to track the latest 'block number' -// known to the server. The server supports two methods: -// -// eth_getBlockByNumber("latest", {}) -// returns the latest block object. -// -// eth_subscribe("newBlocks") -// creates a subscription which fires block objects when new blocks arrive. - -type Block struct { - Number *big.Int -} - -func ExampleClientSubscription() { - // Connect the client. - client, _ := rpc.Dial("ws://127.0.0.1:8485") - subch := make(chan Block) - - // Ensure that subch receives the latest block. - go func() { - for i := 0; ; i++ { - if i > 0 { - time.Sleep(2 * time.Second) - } - subscribeBlocks(client, subch) - } - }() - - // Print events from the subscription as they arrive. - for block := range subch { - fmt.Println("latest block:", block.Number) - } -} - -// subscribeBlocks runs in its own goroutine and maintains -// a subscription for new blocks. -func subscribeBlocks(client *rpc.Client, subch chan Block) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Subscribe to new blocks. - sub, err := client.EthSubscribe(ctx, subch, "newHeads") - if err != nil { - fmt.Println("subscribe error:", err) - return - } - - // The connection is established now. - // Update the channel with the current block. - var lastBlock Block - if err := client.CallContext(ctx, &lastBlock, "eth_getBlockByNumber", "latest"); err != nil { - fmt.Println("can't get latest block:", err) - return - } - subch <- lastBlock - - // The subscription will deliver events to the channel. Wait for the - // subscription to end for any reason, then loop around to re-establish - // the connection. - fmt.Println("connection lost: ", <-sub.Err()) -} diff --git a/rpc/client_test.go b/rpc/client_test.go deleted file mode 100644 index 79ea32e..0000000 --- a/rpc/client_test.go +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "context" - "fmt" - "math/rand" - "net" - "net/http" - "net/http/httptest" - "os" - "reflect" - "runtime" - "sync" - "testing" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/ava-labs/go-ethereum/log" -) - -func TestClientRequest(t *testing.T) { - server := newTestServer() - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - var resp Result - if err := client.Call(&resp, "test_echo", "hello", 10, &Args{"world"}); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(resp, Result{"hello", 10, &Args{"world"}}) { - t.Errorf("incorrect result %#v", resp) - } -} - -func TestClientBatchRequest(t *testing.T) { - server := newTestServer() - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - batch := []BatchElem{ - { - Method: "test_echo", - Args: []interface{}{"hello", 10, &Args{"world"}}, - Result: new(Result), - }, - { - Method: "test_echo", - Args: []interface{}{"hello2", 11, &Args{"world"}}, - Result: new(Result), - }, - { - Method: "no_such_method", - Args: []interface{}{1, 2, 3}, - Result: new(int), - }, - } - if err := client.BatchCall(batch); err != nil { - t.Fatal(err) - } - wantResult := []BatchElem{ - { - Method: "test_echo", - Args: []interface{}{"hello", 10, &Args{"world"}}, - Result: &Result{"hello", 10, &Args{"world"}}, - }, - { - Method: "test_echo", - Args: []interface{}{"hello2", 11, &Args{"world"}}, - Result: &Result{"hello2", 11, &Args{"world"}}, - }, - { - Method: "no_such_method", - Args: []interface{}{1, 2, 3}, - Result: new(int), - Error: &jsonError{Code: -32601, Message: "the method no_such_method does not exist/is not available"}, - }, - } - if !reflect.DeepEqual(batch, wantResult) { - t.Errorf("batch results mismatch:\ngot %swant %s", spew.Sdump(batch), spew.Sdump(wantResult)) - } -} - -func TestClientNotify(t *testing.T) { - server := newTestServer() - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - if err := client.Notify(context.Background(), "test_echo", "hello", 10, &Args{"world"}); err != nil { - t.Fatal(err) - } -} - -// func TestClientCancelInproc(t *testing.T) { testClientCancel("inproc", t) } -func TestClientCancelWebsocket(t *testing.T) { testClientCancel("ws", t) } -func TestClientCancelHTTP(t *testing.T) { testClientCancel("http", t) } -func TestClientCancelIPC(t *testing.T) { testClientCancel("ipc", t) } - -// This test checks that requests made through CallContext can be canceled by canceling -// the context. -func testClientCancel(transport string, t *testing.T) { - // These tests take a lot of time, run them all at once. - // You probably want to run with -parallel 1 or comment out - // the call to t.Parallel if you enable the logging. - t.Parallel() - - server := newTestServer() - defer server.Stop() - - // What we want to achieve is that the context gets canceled - // at various stages of request processing. The interesting cases - // are: - // - cancel during dial - // - cancel while performing a HTTP request - // - cancel while waiting for a response - // - // To trigger those, the times are chosen such that connections - // are killed within the deadline for every other call (maxKillTimeout - // is 2x maxCancelTimeout). - // - // Once a connection is dead, there is a fair chance it won't connect - // successfully because the accept is delayed by 1s. - maxContextCancelTimeout := 300 * time.Millisecond - fl := &flakeyListener{ - maxAcceptDelay: 1 * time.Second, - maxKillTimeout: 600 * time.Millisecond, - } - - var client *Client - switch transport { - case "ws", "http": - c, hs := httpTestClient(server, transport, fl) - defer hs.Close() - client = c - case "ipc": - c, l := ipcTestClient(server, fl) - defer l.Close() - client = c - default: - panic("unknown transport: " + transport) - } - - // The actual test starts here. - var ( - wg sync.WaitGroup - nreqs = 10 - ncallers = 6 - ) - caller := func(index int) { - defer wg.Done() - for i := 0; i < nreqs; i++ { - var ( - ctx context.Context - cancel func() - timeout = time.Duration(rand.Int63n(int64(maxContextCancelTimeout))) - ) - if index < ncallers/2 { - // For half of the callers, create a context without deadline - // and cancel it later. - ctx, cancel = context.WithCancel(context.Background()) - time.AfterFunc(timeout, cancel) - } else { - // For the other half, create a context with a deadline instead. This is - // different because the context deadline is used to set the socket write - // deadline. - ctx, cancel = context.WithTimeout(context.Background(), timeout) - } - // Now perform a call with the context. - // The key thing here is that no call will ever complete successfully. - sleepTime := maxContextCancelTimeout + 20*time.Millisecond - err := client.CallContext(ctx, nil, "test_sleep", sleepTime) - if err != nil { - log.Debug(fmt.Sprint("got expected error:", err)) - } else { - t.Errorf("no error for call with %v wait time", timeout) - } - cancel() - } - } - wg.Add(ncallers) - for i := 0; i < ncallers; i++ { - go caller(i) - } - wg.Wait() -} - -func TestClientSubscribeInvalidArg(t *testing.T) { - server := newTestServer() - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - check := func(shouldPanic bool, arg interface{}) { - defer func() { - err := recover() - if shouldPanic && err == nil { - t.Errorf("EthSubscribe should've panicked for %#v", arg) - } - if !shouldPanic && err != nil { - t.Errorf("EthSubscribe shouldn't have panicked for %#v", arg) - buf := make([]byte, 1024*1024) - buf = buf[:runtime.Stack(buf, false)] - t.Error(err) - t.Error(string(buf)) - } - }() - client.EthSubscribe(context.Background(), arg, "foo_bar") - } - check(true, nil) - check(true, 1) - check(true, (chan int)(nil)) - check(true, make(<-chan int)) - check(false, make(chan int)) - check(false, make(chan<- int)) -} - -func TestClientSubscribe(t *testing.T) { - server := newTestServer() - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - nc := make(chan int) - count := 10 - sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", count, 0) - if err != nil { - t.Fatal("can't subscribe:", err) - } - for i := 0; i < count; i++ { - if val := <-nc; val != i { - t.Fatalf("value mismatch: got %d, want %d", val, i) - } - } - - sub.Unsubscribe() - select { - case v := <-nc: - t.Fatal("received value after unsubscribe:", v) - case err := <-sub.Err(): - if err != nil { - t.Fatalf("Err returned a non-nil error after explicit unsubscribe: %q", err) - } - case <-time.After(1 * time.Second): - t.Fatalf("subscription not closed within 1s after unsubscribe") - } -} - -// In this test, the connection drops while Subscribe is waiting for a response. -func TestClientSubscribeClose(t *testing.T) { - server := newTestServer() - service := ¬ificationTestService{ - gotHangSubscriptionReq: make(chan struct{}), - unblockHangSubscription: make(chan struct{}), - } - if err := server.RegisterName("nftest2", service); err != nil { - t.Fatal(err) - } - - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - var ( - nc = make(chan int) - errc = make(chan error) - sub *ClientSubscription - err error - ) - go func() { - sub, err = client.Subscribe(context.Background(), "nftest2", nc, "hangSubscription", 999) - errc <- err - }() - - <-service.gotHangSubscriptionReq - client.Close() - service.unblockHangSubscription <- struct{}{} - - select { - case err := <-errc: - if err == nil { - t.Errorf("Subscribe returned nil error after Close") - } - if sub != nil { - t.Error("Subscribe returned non-nil subscription after Close") - } - case <-time.After(1 * time.Second): - t.Fatalf("Subscribe did not return within 1s after Close") - } -} - -// This test reproduces https://github.com/ethereum/go-ethereum/issues/17837 where the -// client hangs during shutdown when Unsubscribe races with Client.Close. -func TestClientCloseUnsubscribeRace(t *testing.T) { - server := newTestServer() - defer server.Stop() - - for i := 0; i < 20; i++ { - client := DialInProc(server) - nc := make(chan int) - sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", 3, 1) - if err != nil { - t.Fatal(err) - } - go client.Close() - go sub.Unsubscribe() - select { - case <-sub.Err(): - case <-time.After(5 * time.Second): - t.Fatal("subscription not closed within timeout") - } - } -} - -// This test checks that Client doesn't lock up when a single subscriber -// doesn't read subscription events. -func TestClientNotificationStorm(t *testing.T) { - server := newTestServer() - defer server.Stop() - - doTest := func(count int, wantError bool) { - client := DialInProc(server) - defer client.Close() - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Subscribe on the server. It will start sending many notifications - // very quickly. - nc := make(chan int) - sub, err := client.Subscribe(ctx, "nftest", nc, "someSubscription", count, 0) - if err != nil { - t.Fatal("can't subscribe:", err) - } - defer sub.Unsubscribe() - - // Process each notification, try to run a call in between each of them. - for i := 0; i < count; i++ { - select { - case val := <-nc: - if val != i { - t.Fatalf("(%d/%d) unexpected value %d", i, count, val) - } - case err := <-sub.Err(): - if wantError && err != ErrSubscriptionQueueOverflow { - t.Fatalf("(%d/%d) got error %q, want %q", i, count, err, ErrSubscriptionQueueOverflow) - } else if !wantError { - t.Fatalf("(%d/%d) got unexpected error %q", i, count, err) - } - return - } - var r int - err := client.CallContext(ctx, &r, "nftest_echo", i) - if err != nil { - if !wantError { - t.Fatalf("(%d/%d) call error: %v", i, count, err) - } - return - } - } - if wantError { - t.Fatalf("didn't get expected error") - } - } - - doTest(8000, false) - doTest(21000, true) -} - -func TestClientHTTP(t *testing.T) { - server := newTestServer() - defer server.Stop() - - client, hs := httpTestClient(server, "http", nil) - defer hs.Close() - defer client.Close() - - // Launch concurrent requests. - var ( - results = make([]Result, 100) - errc = make(chan error) - wantResult = Result{"a", 1, new(Args)} - ) - defer client.Close() - for i := range results { - i := i - go func() { - errc <- client.Call(&results[i], "test_echo", - wantResult.String, wantResult.Int, wantResult.Args) - }() - } - - // Wait for all of them to complete. - timeout := time.NewTimer(5 * time.Second) - defer timeout.Stop() - for i := range results { - select { - case err := <-errc: - if err != nil { - t.Fatal(err) - } - case <-timeout.C: - t.Fatalf("timeout (got %d/%d) results)", i+1, len(results)) - } - } - - // Check results. - for i := range results { - if !reflect.DeepEqual(results[i], wantResult) { - t.Errorf("result %d mismatch: got %#v, want %#v", i, results[i], wantResult) - } - } -} - -func TestClientReconnect(t *testing.T) { - startServer := func(addr string) (*Server, net.Listener) { - srv := newTestServer() - l, err := net.Listen("tcp", addr) - if err != nil { - t.Fatal("can't listen:", err) - } - go http.Serve(l, srv.WebsocketHandler([]string{"*"})) - return srv, l - } - - ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second) - defer cancel() - - // Start a server and corresponding client. - s1, l1 := startServer("127.0.0.1:0") - client, err := DialContext(ctx, "ws://"+l1.Addr().String()) - if err != nil { - t.Fatal("can't dial", err) - } - - // Perform a call. This should work because the server is up. - var resp Result - if err := client.CallContext(ctx, &resp, "test_echo", "", 1, nil); err != nil { - t.Fatal(err) - } - - // Shut down the server and allow for some cool down time so we can listen on the same - // address again. - l1.Close() - s1.Stop() - time.Sleep(2 * time.Second) - - // Try calling again. It shouldn't work. - if err := client.CallContext(ctx, &resp, "test_echo", "", 2, nil); err == nil { - t.Error("successful call while the server is down") - t.Logf("resp: %#v", resp) - } - - // Start it up again and call again. The connection should be reestablished. - // We spawn multiple calls here to check whether this hangs somehow. - s2, l2 := startServer(l1.Addr().String()) - defer l2.Close() - defer s2.Stop() - - start := make(chan struct{}) - errors := make(chan error, 20) - for i := 0; i < cap(errors); i++ { - go func() { - <-start - var resp Result - errors <- client.CallContext(ctx, &resp, "test_echo", "", 3, nil) - }() - } - close(start) - errcount := 0 - for i := 0; i < cap(errors); i++ { - if err = <-errors; err != nil { - errcount++ - } - } - t.Logf("%d errors, last error: %v", errcount, err) - if errcount > 1 { - t.Errorf("expected one error after disconnect, got %d", errcount) - } -} - -func httpTestClient(srv *Server, transport string, fl *flakeyListener) (*Client, *httptest.Server) { - // Create the HTTP server. - var hs *httptest.Server - switch transport { - case "ws": - hs = httptest.NewUnstartedServer(srv.WebsocketHandler([]string{"*"})) - case "http": - hs = httptest.NewUnstartedServer(srv) - default: - panic("unknown HTTP transport: " + transport) - } - // Wrap the listener if required. - if fl != nil { - fl.Listener = hs.Listener - hs.Listener = fl - } - // Connect the client. - hs.Start() - client, err := Dial(transport + "://" + hs.Listener.Addr().String()) - if err != nil { - panic(err) - } - return client, hs -} - -func ipcTestClient(srv *Server, fl *flakeyListener) (*Client, net.Listener) { - // Listen on a random endpoint. - endpoint := fmt.Sprintf("go-ethereum-test-ipc-%d-%d", os.Getpid(), rand.Int63()) - if runtime.GOOS == "windows" { - endpoint = `\\.\pipe\` + endpoint - } else { - endpoint = os.TempDir() + "/" + endpoint - } - l, err := ipcListen(endpoint) - if err != nil { - panic(err) - } - // Connect the listener to the server. - if fl != nil { - fl.Listener = l - l = fl - } - go srv.ServeListener(l) - // Connect the client. - client, err := Dial(endpoint) - if err != nil { - panic(err) - } - return client, l -} - -// flakeyListener kills accepted connections after a random timeout. -type flakeyListener struct { - net.Listener - maxKillTimeout time.Duration - maxAcceptDelay time.Duration -} - -func (l *flakeyListener) Accept() (net.Conn, error) { - delay := time.Duration(rand.Int63n(int64(l.maxAcceptDelay))) - time.Sleep(delay) - - c, err := l.Listener.Accept() - if err == nil { - timeout := time.Duration(rand.Int63n(int64(l.maxKillTimeout))) - time.AfterFunc(timeout, func() { - log.Debug(fmt.Sprintf("killing conn %v after %v", c.LocalAddr(), timeout)) - c.Close() - }) - } - return c, err -} diff --git a/rpc/http_test.go b/rpc/http_test.go deleted file mode 100644 index b3f694d..0000000 --- a/rpc/http_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -func TestHTTPErrorResponseWithDelete(t *testing.T) { - testHTTPErrorResponse(t, http.MethodDelete, contentType, "", http.StatusMethodNotAllowed) -} - -func TestHTTPErrorResponseWithPut(t *testing.T) { - testHTTPErrorResponse(t, http.MethodPut, contentType, "", http.StatusMethodNotAllowed) -} - -func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) { - body := make([]rune, maxRequestContentLength+1) - testHTTPErrorResponse(t, - http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge) -} - -func TestHTTPErrorResponseWithEmptyContentType(t *testing.T) { - testHTTPErrorResponse(t, http.MethodPost, "", "", http.StatusUnsupportedMediaType) -} - -func TestHTTPErrorResponseWithValidRequest(t *testing.T) { - testHTTPErrorResponse(t, http.MethodPost, contentType, "", 0) -} - -func testHTTPErrorResponse(t *testing.T, method, contentType, body string, expected int) { - request := httptest.NewRequest(method, "http://url.com", strings.NewReader(body)) - request.Header.Set("content-type", contentType) - if code, _ := validateRequest(request); code != expected { - t.Fatalf("response code should be %d not %d", expected, code) - } -} diff --git a/rpc/server_test.go b/rpc/server_test.go deleted file mode 100644 index 3909954..0000000 --- a/rpc/server_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "bufio" - "bytes" - "io" - "io/ioutil" - "net" - "path/filepath" - "strings" - "testing" - "time" -) - -func TestServerRegisterName(t *testing.T) { - server := NewServer() - service := new(testService) - - if err := server.RegisterName("test", service); err != nil { - t.Fatalf("%v", err) - } - - if len(server.services.services) != 2 { - t.Fatalf("Expected 2 service entries, got %d", len(server.services.services)) - } - - svc, ok := server.services.services["test"] - if !ok { - t.Fatalf("Expected service calc to be registered") - } - - wantCallbacks := 7 - if len(svc.callbacks) != wantCallbacks { - t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks)) - } -} - -func TestServer(t *testing.T) { - files, err := ioutil.ReadDir("testdata") - if err != nil { - t.Fatal("where'd my testdata go?") - } - for _, f := range files { - if f.IsDir() || strings.HasPrefix(f.Name(), ".") { - continue - } - path := filepath.Join("testdata", f.Name()) - name := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) - t.Run(name, func(t *testing.T) { - runTestScript(t, path) - }) - } -} - -func runTestScript(t *testing.T, file string) { - server := newTestServer() - content, err := ioutil.ReadFile(file) - if err != nil { - t.Fatal(err) - } - - clientConn, serverConn := net.Pipe() - defer clientConn.Close() - go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) - readbuf := bufio.NewReader(clientConn) - for _, line := range strings.Split(string(content), "\n") { - line = strings.TrimSpace(line) - switch { - case len(line) == 0 || strings.HasPrefix(line, "//"): - // skip comments, blank lines - continue - case strings.HasPrefix(line, "--> "): - t.Log(line) - // write to connection - clientConn.SetWriteDeadline(time.Now().Add(5 * time.Second)) - if _, err := io.WriteString(clientConn, line[4:]+"\n"); err != nil { - t.Fatalf("write error: %v", err) - } - case strings.HasPrefix(line, "<-- "): - t.Log(line) - want := line[4:] - // read line from connection and compare text - clientConn.SetReadDeadline(time.Now().Add(5 * time.Second)) - sent, err := readbuf.ReadString('\n') - if err != nil { - t.Fatalf("read error: %v", err) - } - sent = strings.TrimRight(sent, "\r\n") - if sent != want { - t.Errorf("wrong line from server\ngot: %s\nwant: %s", sent, want) - } - default: - panic("invalid line in test script: " + line) - } - } -} - -// This test checks that responses are delivered for very short-lived connections that -// only carry a single request. -func TestServerShortLivedConn(t *testing.T) { - server := newTestServer() - defer server.Stop() - - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal("can't listen:", err) - } - defer listener.Close() - go server.ServeListener(listener) - - var ( - request = `{"jsonrpc":"2.0","id":1,"method":"rpc_modules"}` + "\n" - wantResp = `{"jsonrpc":"2.0","id":1,"result":{"nftest":"1.0","rpc":"1.0","test":"1.0"}}` + "\n" - deadline = time.Now().Add(10 * time.Second) - ) - for i := 0; i < 20; i++ { - conn, err := net.Dial("tcp", listener.Addr().String()) - if err != nil { - t.Fatal("can't dial:", err) - } - defer conn.Close() - conn.SetDeadline(deadline) - // Write the request, then half-close the connection so the server stops reading. - conn.Write([]byte(request)) - conn.(*net.TCPConn).CloseWrite() - // Now try to get the response. - buf := make([]byte, 2000) - n, err := conn.Read(buf) - if err != nil { - t.Fatal("read error:", err) - } - if !bytes.Equal(buf[:n], []byte(wantResp)) { - t.Fatalf("wrong response: %s", buf[:n]) - } - } -} diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go deleted file mode 100644 index eba1924..0000000 --- a/rpc/subscription_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "encoding/json" - "fmt" - "net" - "strings" - "testing" - "time" -) - -func TestNewID(t *testing.T) { - hexchars := "0123456789ABCDEFabcdef" - for i := 0; i < 100; i++ { - id := string(NewID()) - if !strings.HasPrefix(id, "0x") { - t.Fatalf("invalid ID prefix, want '0x...', got %s", id) - } - - id = id[2:] - if len(id) == 0 || len(id) > 32 { - t.Fatalf("invalid ID length, want len(id) > 0 && len(id) <= 32), got %d", len(id)) - } - - for i := 0; i < len(id); i++ { - if strings.IndexByte(hexchars, id[i]) == -1 { - t.Fatalf("unexpected byte, want any valid hex char, got %c", id[i]) - } - } - } -} - -func TestSubscriptions(t *testing.T) { - var ( - namespaces = []string{"eth", "shh", "bzz"} - service = ¬ificationTestService{} - subCount = len(namespaces) - notificationCount = 3 - - server = NewServer() - clientConn, serverConn = net.Pipe() - out = json.NewEncoder(clientConn) - in = json.NewDecoder(clientConn) - successes = make(chan subConfirmation) - notifications = make(chan subscriptionResult) - errors = make(chan error, subCount*notificationCount+1) - ) - - // setup and start server - for _, namespace := range namespaces { - if err := server.RegisterName(namespace, service); err != nil { - t.Fatalf("unable to register test service %v", err) - } - } - go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) - defer server.Stop() - - // wait for message and write them to the given channels - go waitForMessages(in, successes, notifications, errors) - - // create subscriptions one by one - for i, namespace := range namespaces { - request := map[string]interface{}{ - "id": i, - "method": fmt.Sprintf("%s_subscribe", namespace), - "version": "2.0", - "params": []interface{}{"someSubscription", notificationCount, i}, - } - if err := out.Encode(&request); err != nil { - t.Fatalf("Could not create subscription: %v", err) - } - } - - timeout := time.After(30 * time.Second) - subids := make(map[string]string, subCount) - count := make(map[string]int, subCount) - allReceived := func() bool { - done := len(count) == subCount - for _, c := range count { - if c < notificationCount { - done = false - } - } - return done - } - for !allReceived() { - select { - case confirmation := <-successes: // subscription created - subids[namespaces[confirmation.reqid]] = string(confirmation.subid) - case notification := <-notifications: - count[notification.ID]++ - case err := <-errors: - t.Fatal(err) - case <-timeout: - for _, namespace := range namespaces { - subid, found := subids[namespace] - if !found { - t.Errorf("subscription for %q not created", namespace) - continue - } - if count, found := count[subid]; !found || count < notificationCount { - t.Errorf("didn't receive all notifications (%d<%d) in time for namespace %q", count, notificationCount, namespace) - } - } - t.Fatal("timed out") - } - } -} - -// This test checks that unsubscribing works. -func TestServerUnsubscribe(t *testing.T) { - // Start the server. - server := newTestServer() - service := ¬ificationTestService{unsubscribed: make(chan string)} - server.RegisterName("nftest2", service) - p1, p2 := net.Pipe() - go server.ServeCodec(NewJSONCodec(p1), OptionMethodInvocation|OptionSubscriptions) - - p2.SetDeadline(time.Now().Add(10 * time.Second)) - - // Subscribe. - p2.Write([]byte(`{"jsonrpc":"2.0","id":1,"method":"nftest2_subscribe","params":["someSubscription",0,10]}`)) - - // Handle received messages. - resps := make(chan subConfirmation) - notifications := make(chan subscriptionResult) - errors := make(chan error) - go waitForMessages(json.NewDecoder(p2), resps, notifications, errors) - - // Receive the subscription ID. - var sub subConfirmation - select { - case sub = <-resps: - case err := <-errors: - t.Fatal(err) - } - - // Unsubscribe and check that it is handled on the server side. - p2.Write([]byte(`{"jsonrpc":"2.0","method":"nftest2_unsubscribe","params":["` + sub.subid + `"]}`)) - for { - select { - case id := <-service.unsubscribed: - if id != string(sub.subid) { - t.Errorf("wrong subscription ID unsubscribed") - } - return - case err := <-errors: - t.Fatal(err) - case <-notifications: - // drop notifications - } - } -} - -type subConfirmation struct { - reqid int - subid ID -} - -func waitForMessages(in *json.Decoder, successes chan subConfirmation, notifications chan subscriptionResult, errors chan error) { - for { - var msg jsonrpcMessage - if err := in.Decode(&msg); err != nil { - errors <- fmt.Errorf("decode error: %v", err) - return - } - switch { - case msg.isNotification(): - var res subscriptionResult - if err := json.Unmarshal(msg.Params, &res); err != nil { - errors <- fmt.Errorf("invalid subscription result: %v", err) - } else { - notifications <- res - } - case msg.isResponse(): - var c subConfirmation - if msg.Error != nil { - errors <- msg.Error - } else if err := json.Unmarshal(msg.Result, &c.subid); err != nil { - errors <- fmt.Errorf("invalid response: %v", err) - } else { - json.Unmarshal(msg.ID, &c.reqid) - successes <- c - } - default: - errors <- fmt.Errorf("unrecognized message: %v", msg) - return - } - } -} diff --git a/rpc/testservice_test.go b/rpc/testservice_test.go deleted file mode 100644 index 98871b5..0000000 --- a/rpc/testservice_test.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "context" - "encoding/binary" - "errors" - "sync" - "time" -) - -func newTestServer() *Server { - server := NewServer() - server.idgen = sequentialIDGenerator() - if err := server.RegisterName("test", new(testService)); err != nil { - panic(err) - } - if err := server.RegisterName("nftest", new(notificationTestService)); err != nil { - panic(err) - } - return server -} - -func sequentialIDGenerator() func() ID { - var ( - mu sync.Mutex - counter uint64 - ) - return func() ID { - mu.Lock() - defer mu.Unlock() - counter++ - id := make([]byte, 8) - binary.BigEndian.PutUint64(id, counter) - return encodeID(id) - } -} - -type testService struct{} - -type Args struct { - S string -} - -type Result struct { - String string - Int int - Args *Args -} - -func (s *testService) NoArgsRets() {} - -func (s *testService) Echo(str string, i int, args *Args) Result { - return Result{str, i, args} -} - -func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result { - return Result{str, i, args} -} - -func (s *testService) Sleep(ctx context.Context, duration time.Duration) { - time.Sleep(duration) -} - -func (s *testService) Rets() (string, error) { - return "", nil -} - -func (s *testService) InvalidRets1() (error, string) { - return nil, "" -} - -func (s *testService) InvalidRets2() (string, string) { - return "", "" -} - -func (s *testService) InvalidRets3() (string, string, error) { - return "", "", nil -} - -func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { - c, ok := ClientFromContext(ctx) - if !ok { - return nil, errors.New("no client") - } - var result interface{} - err := c.Call(&result, method, args...) - return result, err -} - -func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error { - c, ok := ClientFromContext(ctx) - if !ok { - return errors.New("no client") - } - go func() { - <-ctx.Done() - var result interface{} - c.Call(&result, method, args...) - }() - return nil -} - -func (s *testService) Subscription(ctx context.Context) (*Subscription, error) { - return nil, nil -} - -type notificationTestService struct { - unsubscribed chan string - gotHangSubscriptionReq chan struct{} - unblockHangSubscription chan struct{} -} - -func (s *notificationTestService) Echo(i int) int { - return i -} - -func (s *notificationTestService) Unsubscribe(subid string) { - if s.unsubscribed != nil { - s.unsubscribed <- subid - } -} - -func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { - notifier, supported := NotifierFromContext(ctx) - if !supported { - return nil, ErrNotificationsUnsupported - } - - // By explicitly creating an subscription we make sure that the subscription id is send - // back to the client before the first subscription.Notify is called. Otherwise the - // events might be send before the response for the *_subscribe method. - subscription := notifier.CreateSubscription() - go func() { - for i := 0; i < n; i++ { - if err := notifier.Notify(subscription.ID, val+i); err != nil { - return - } - } - select { - case <-notifier.Closed(): - case <-subscription.Err(): - } - if s.unsubscribed != nil { - s.unsubscribed <- string(subscription.ID) - } - }() - return subscription, nil -} - -// HangSubscription blocks on s.unblockHangSubscription before sending anything. -func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { - notifier, supported := NotifierFromContext(ctx) - if !supported { - return nil, ErrNotificationsUnsupported - } - s.gotHangSubscriptionReq <- struct{}{} - <-s.unblockHangSubscription - subscription := notifier.CreateSubscription() - - go func() { - notifier.Notify(subscription.ID, val) - }() - return subscription, nil -} diff --git a/rpc/types_test.go b/rpc/types_test.go deleted file mode 100644 index 0465849..0000000 --- a/rpc/types_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "encoding/json" - "testing" - - "github.com/ava-labs/go-ethereum/common/math" -) - -func TestBlockNumberJSONUnmarshal(t *testing.T) { - tests := []struct { - input string - mustFail bool - expected BlockNumber - }{ - 0: {`"0x"`, true, BlockNumber(0)}, - 1: {`"0x0"`, false, BlockNumber(0)}, - 2: {`"0X1"`, false, BlockNumber(1)}, - 3: {`"0x00"`, true, BlockNumber(0)}, - 4: {`"0x01"`, true, BlockNumber(0)}, - 5: {`"0x1"`, false, BlockNumber(1)}, - 6: {`"0x12"`, false, BlockNumber(18)}, - 7: {`"0x7fffffffffffffff"`, false, BlockNumber(math.MaxInt64)}, - 8: {`"0x8000000000000000"`, true, BlockNumber(0)}, - 9: {"0", true, BlockNumber(0)}, - 10: {`"ff"`, true, BlockNumber(0)}, - 11: {`"pending"`, false, PendingBlockNumber}, - 12: {`"latest"`, false, LatestBlockNumber}, - 13: {`"earliest"`, false, EarliestBlockNumber}, - 14: {`someString`, true, BlockNumber(0)}, - 15: {`""`, true, BlockNumber(0)}, - 16: {``, true, BlockNumber(0)}, - } - - for i, test := range tests { - var num BlockNumber - err := json.Unmarshal([]byte(test.input), &num) - if test.mustFail && err == nil { - t.Errorf("Test %d should fail", i) - continue - } - if !test.mustFail && err != nil { - t.Errorf("Test %d should pass but got err: %v", i, err) - continue - } - if num != test.expected { - t.Errorf("Test %d got unexpected value, want %d, got %d", i, test.expected, num) - } - } -} diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go deleted file mode 100644 index 9dc1084..0000000 --- a/rpc/websocket_test.go +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "context" - "net" - "net/http" - "net/http/httptest" - "reflect" - "strings" - "testing" - "time" - - "github.com/gorilla/websocket" -) - -func TestWebsocketClientHeaders(t *testing.T) { - t.Parallel() - - endpoint, header, err := wsClientHeaders("wss://testuser:test-PASS_01@example.com:1234", "https://example.com") - if err != nil { - t.Fatalf("wsGetConfig failed: %s", err) - } - if endpoint != "wss://example.com:1234" { - t.Fatal("User should have been stripped from the URL") - } - if header.Get("authorization") != "Basic dGVzdHVzZXI6dGVzdC1QQVNTXzAx" { - t.Fatal("Basic auth header is incorrect") - } - if header.Get("origin") != "https://example.com" { - t.Fatal("Origin not set") - } -} - -// This test checks that the server rejects connections from disallowed origins. -func TestWebsocketOriginCheck(t *testing.T) { - t.Parallel() - - var ( - srv = newTestServer() - httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"http://example.com"})) - wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") - ) - defer srv.Stop() - defer httpsrv.Close() - - client, err := DialWebsocket(context.Background(), wsURL, "http://ekzample.com") - if err == nil { - client.Close() - t.Fatal("no error for wrong origin") - } - wantErr := wsHandshakeError{websocket.ErrBadHandshake, "403 Forbidden"} - if !reflect.DeepEqual(err, wantErr) { - t.Fatalf("wrong error for wrong origin: %q", err) - } - - // Connections without origin header should work. - client, err = DialWebsocket(context.Background(), wsURL, "") - if err != nil { - t.Fatal("error for empty origin") - } - client.Close() -} - -// This test checks whether calls exceeding the request size limit are rejected. -func TestWebsocketLargeCall(t *testing.T) { - t.Parallel() - - var ( - srv = newTestServer() - httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"})) - wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") - ) - defer srv.Stop() - defer httpsrv.Close() - - client, err := DialWebsocket(context.Background(), wsURL, "") - if err != nil { - t.Fatalf("can't dial: %v", err) - } - defer client.Close() - - // This call sends slightly less than the limit and should work. - var result Result - arg := strings.Repeat("x", maxRequestContentLength-200) - if err := client.Call(&result, "test_echo", arg, 1); err != nil { - t.Fatalf("valid call didn't work: %v", err) - } - if result.String != arg { - t.Fatal("wrong string echoed") - } - - // This call sends twice the allowed size and shouldn't work. - arg = strings.Repeat("x", maxRequestContentLength*2) - err = client.Call(&result, "test_echo", arg) - if err == nil { - t.Fatal("no error for too large call") - } -} - -// This test checks that client handles WebSocket ping frames correctly. -func TestClientWebsocketPing(t *testing.T) { - t.Parallel() - - var ( - sendPing = make(chan struct{}) - server = wsPingTestServer(t, sendPing) - ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) - ) - defer cancel() - defer server.Shutdown(ctx) - - client, err := DialContext(ctx, "ws://"+server.Addr) - if err != nil { - t.Fatalf("client dial error: %v", err) - } - resultChan := make(chan int) - sub, err := client.EthSubscribe(ctx, resultChan, "foo") - if err != nil { - t.Fatalf("client subscribe error: %v", err) - } - - // Wait for the context's deadline to be reached before proceeding. - // This is important for reproducing https://github.com/ethereum/go-ethereum/issues/19798 - <-ctx.Done() - close(sendPing) - - // Wait for the subscription result. - timeout := time.NewTimer(5 * time.Second) - for { - select { - case err := <-sub.Err(): - t.Error("client subscription error:", err) - case result := <-resultChan: - t.Log("client got result:", result) - return - case <-timeout.C: - t.Error("didn't get any result within the test timeout") - return - } - } -} - -// wsPingTestServer runs a WebSocket server which accepts a single subscription request. -// When a value arrives on sendPing, the server sends a ping frame, waits for a matching -// pong and finally delivers a single subscription result. -func wsPingTestServer(t *testing.T, sendPing <-chan struct{}) *http.Server { - var srv http.Server - shutdown := make(chan struct{}) - srv.RegisterOnShutdown(func() { - close(shutdown) - }) - srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Upgrade to WebSocket. - upgrader := websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { return true }, - } - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - t.Errorf("server WS upgrade error: %v", err) - return - } - defer conn.Close() - - // Handle the connection. - wsPingTestHandler(t, conn, shutdown, sendPing) - }) - - // Start the server. - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal("can't listen:", err) - } - srv.Addr = listener.Addr().String() - go srv.Serve(listener) - return &srv -} - -func wsPingTestHandler(t *testing.T, conn *websocket.Conn, shutdown, sendPing <-chan struct{}) { - // Canned responses for the eth_subscribe call in TestClientWebsocketPing. - const ( - subResp = `{"jsonrpc":"2.0","id":1,"result":"0x00"}` - subNotify = `{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x00","result":1}}` - ) - - // Handle subscribe request. - if _, _, err := conn.ReadMessage(); err != nil { - t.Errorf("server read error: %v", err) - return - } - if err := conn.WriteMessage(websocket.TextMessage, []byte(subResp)); err != nil { - t.Errorf("server write error: %v", err) - return - } - - // Read from the connection to process control messages. - var pongCh = make(chan string) - conn.SetPongHandler(func(d string) error { - t.Logf("server got pong: %q", d) - pongCh <- d - return nil - }) - go func() { - for { - typ, msg, err := conn.ReadMessage() - if err != nil { - return - } - t.Logf("server got message (%d): %q", typ, msg) - } - }() - - // Write messages. - var ( - sendResponse <-chan time.Time - wantPong string - ) - for { - select { - case _, open := <-sendPing: - if !open { - sendPing = nil - } - t.Logf("server sending ping") - conn.WriteMessage(websocket.PingMessage, []byte("ping")) - wantPong = "ping" - case data := <-pongCh: - if wantPong == "" { - t.Errorf("unexpected pong") - } else if data != wantPong { - t.Errorf("got pong with wrong data %q", data) - } - wantPong = "" - sendResponse = time.NewTimer(200 * time.Millisecond).C - case <-sendResponse: - t.Logf("server sending response") - conn.WriteMessage(websocket.TextMessage, []byte(subNotify)) - sendResponse = nil - case <-shutdown: - conn.Close() - return - } - } -} -- cgit v1.2.3-70-g09d2 From 2d396b3c69a26e4096ccb376c012911d299c68c7 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 1 Jul 2020 17:29:39 -0400 Subject: make sure getBalance() works --- core/genesis.go | 1 - core/vm/instructions.go | 2 -- examples/multicoin/main.go | 11 ++++++++++- examples/multicoin/mc_test.sol | 5 +++-- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'core/vm') diff --git a/core/genesis.go b/core/genesis.go index 7378a53..ef490bf 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -266,7 +266,6 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { } if account.MCBalance != nil { statedb.ForceEnableMultiCoin(addr) - fmt.Println("enable", addr.Hex()) for coinID, value := range account.MCBalance { statedb.AddBalanceMultiCoin(addr, coinID, value) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 91233b3..ecdccbd 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -18,7 +18,6 @@ package vm import ( "errors" - "fmt" "math/big" "github.com/ava-labs/coreth/core/types" @@ -418,7 +417,6 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo func opBalanceMultiCoin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { addr, cid := stack.pop(), stack.pop() - fmt.Println(addr, cid) stack.push(interpreter.evm.StateDB.GetBalanceMultiCoin(common.BigToAddress(addr), common.BigToHash(cid))) return nil, nil } diff --git a/examples/multicoin/main.go b/examples/multicoin/main.go index ad23e32..9d1970a 100644 --- a/examples/multicoin/main.go +++ b/examples/multicoin/main.go @@ -55,7 +55,7 @@ func main() { bob, _ := coreth.NewKey(rand.Reader) g := new(core.Genesis) - b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003373ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea2646970667358221220477c0e55c25708d36d55abae8a51496c16bc5d28bc1ee6a9963c304afbacdc3464736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` + b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003073ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea26469706673582212200bc9fda886770285cc0f33cf0c674c080debc2ad79572ecf0c9f20d729b9487264736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` k := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" err := json.Unmarshal([]byte(b), g) checkError(err) @@ -149,6 +149,15 @@ func main() { chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ } + code, err = a.Pack("updateBalance", big.NewInt(0)) + tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) + signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) + checkError(err) + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + nonce++ + + checkError(err) + }() } return false diff --git a/examples/multicoin/mc_test.sol b/examples/multicoin/mc_test.sol index 031cba0..a7d468e 100644 --- a/examples/multicoin/mc_test.sol +++ b/examples/multicoin/mc_test.sol @@ -2,16 +2,17 @@ pragma solidity >=0.6.0; contract MCTest { address constant MultiCoin = 0x0100000000000000000000000000000000000000; + uint256 balance; constructor() public { // enable multi-coin functionality (it is disabled by default) (bool success,) = MultiCoin.delegatecall(abi.encodeWithSignature("enableMultiCoin()")); require(success); } - function getBalance(uint256 coinid) public returns (uint256) { + function updateBalance(uint256 coinid) public { (bool success, bytes memory data) = MultiCoin.delegatecall(abi.encodeWithSignature("getBalance(uint256)", coinid)); require(success); - return abi.decode(data, (uint256)); + balance = abi.decode(data, (uint256)); } function deposit() public payable {} -- cgit v1.2.3-70-g09d2 From ca6847998d867dc5d66e76a03bda9c72ae8d287b Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 2 Jul 2020 01:36:18 -0400 Subject: make MultiCoin.transfer work --- core/vm/interpreter.go | 2 +- core/vm/jump_table.go | 3 ++- core/vm/memory_table.go | 16 ++++++++++++++++ examples/multicoin/main.go | 10 +++++++--- examples/multicoin/mc_test.sol | 8 ++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) (limited to 'core/vm') diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 007e5e3..3d388d6 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -220,7 +220,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // for a call operation is the value. Transferring value from one // account to the others means the state is modified and should also // return with an error. - if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) { + if operation.writes || ((op == CALL || op == CALLEX) && stack.Back(2).Sign() != 0) { return nil, errWriteProtection } } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 359b753..737dd14 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -183,6 +183,7 @@ func newTangerineWhistleInstructionSet() JumpTable { instructionSet[SLOAD].constantGas = params.SloadGasEIP150 instructionSet[EXTCODECOPY].constantGas = params.ExtcodeCopyBaseEIP150 instructionSet[CALL].constantGas = params.CallGasEIP150 + instructionSet[CALLEX].constantGas = params.CallGasEIP150 instructionSet[CALLCODE].constantGas = params.CallGasEIP150 instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 return instructionSet @@ -1147,7 +1148,7 @@ func newFrontierInstructionSet() JumpTable { dynamicGas: gasCall, minStack: minStack(9, 1), maxStack: maxStack(9, 1), - memorySize: memoryCall, + memorySize: memoryCallExpert, valid: true, returns: true, }, diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 4fcb414..047f610 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -70,6 +70,22 @@ func memoryCall(stack *Stack) (uint64, bool) { } return y, false } + +func memoryCallExpert(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(7), stack.Back(8)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(5), stack.Back(6)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} + func memoryDelegateCall(stack *Stack) (uint64, bool) { x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) if overflow { diff --git a/examples/multicoin/main.go b/examples/multicoin/main.go index 9d1970a..403db4d 100644 --- a/examples/multicoin/main.go +++ b/examples/multicoin/main.go @@ -55,7 +55,7 @@ func main() { bob, _ := coreth.NewKey(rand.Reader) g := new(core.Genesis) - b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003073ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea26469706673582212200bc9fda886770285cc0f33cf0c674c080debc2ad79572ecf0c9f20d729b9487264736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` + b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003073ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea2646970667358221220ed2100d6623a884d196eceefabe5e03da4309a2562bb25262f3874f1acb31cd764736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` k := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" err := json.Unmarshal([]byte(b), g) checkError(err) @@ -149,15 +149,19 @@ func main() { chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ } - code, err = a.Pack("updateBalance", big.NewInt(0)) + code, err = a.Pack("withdraw", big.NewInt(0), big.NewInt(0), big.NewInt(10000000000000000)) tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ + code, err = a.Pack("updateBalance", big.NewInt(0)) + tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) + signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) - + chain.AddRemoteTxs([]*types.Transaction{signedTx}) + nonce++ }() } return false diff --git a/examples/multicoin/mc_test.sol b/examples/multicoin/mc_test.sol index a7d468e..bfd42a5 100644 --- a/examples/multicoin/mc_test.sol +++ b/examples/multicoin/mc_test.sol @@ -16,4 +16,12 @@ contract MCTest { } function deposit() public payable {} + + function withdraw(uint256 amount, uint256 coinid, uint256 amount2) public { + (bool success,) = MultiCoin.delegatecall( + abi.encodeWithSignature("transfer(address,uint256,uint256,uint256)", + msg.sender, amount, coinid, amount2)); + + require(success); + } } -- cgit v1.2.3-70-g09d2 From 1f49826de2bb8bb4f5f99f69fd2beb039b1172d9 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 29 Jul 2020 12:01:05 -0400 Subject: clean up --- core/state_transition.go | 8 +- core/types/gen_tx_json.go | 12 -- core/types/transaction.go | 33 +--- core/vm/interpreter.go | 14 ++ eth/api_backend.go | 2 +- eth/backend.go | 2 +- eth/filters/filter.go | 2 +- examples/multicoin/main.go | 77 ++++++---- examples/multicoin/mc_test.sol | 10 +- go.mod | 1 + go.sum | 337 +++++++++++++++++++++++++++++++++++++++++ internal/ethapi/backend.go | 2 +- 12 files changed, 413 insertions(+), 87 deletions(-) create mode 100644 go.sum (limited to 'core/vm') diff --git a/core/state_transition.go b/core/state_transition.go index 7a48597..de7488e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -55,8 +55,6 @@ type StateTransition struct { gasPrice *big.Int initialGas uint64 value *big.Int - coinID *common.Hash - value2 *big.Int data []byte state vm.StateDB evm *vm.EVM @@ -71,8 +69,6 @@ type Message interface { GasPrice() *big.Int Gas() uint64 Value() *big.Int - CoinID() *common.Hash - Value2() *big.Int Nonce() uint64 CheckNonce() bool @@ -124,8 +120,6 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition msg: msg, gasPrice: msg.GasPrice(), value: msg.Value(), - coinID: msg.CoinID(), - value2: msg.Value2(), data: msg.Data(), state: evm.StateDB, } @@ -221,7 +215,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } else { // Increment the nonce for the next transaction st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) - ret, st.gas, vmerr = evm.CallExpert(sender, st.to(), st.data, st.gas, st.value, st.coinID, st.value2) + ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value) } if vmerr != nil { log.Debug("VM returned with error", "err", vmerr) diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index dd0d069..0410632 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -21,8 +21,6 @@ func (t txdata) MarshalJSON() ([]byte, error) { GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` - CoinID *common.Hash `json:"coinid" rlp:"nil"` - Amount2 *hexutil.Big `json:"value2" rlp:"nil"` Payload hexutil.Bytes `json:"input" gencodec:"required"` V *hexutil.Big `json:"v" gencodec:"required"` R *hexutil.Big `json:"r" gencodec:"required"` @@ -35,8 +33,6 @@ func (t txdata) MarshalJSON() ([]byte, error) { enc.GasLimit = hexutil.Uint64(t.GasLimit) enc.Recipient = t.Recipient enc.Amount = (*hexutil.Big)(t.Amount) - enc.CoinID = t.CoinID - enc.Amount2 = (*hexutil.Big)(t.Amount2) enc.Payload = t.Payload enc.V = (*hexutil.Big)(t.V) enc.R = (*hexutil.Big)(t.R) @@ -53,8 +49,6 @@ func (t *txdata) UnmarshalJSON(input []byte) error { GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` - CoinID *common.Hash `json:"coinid" rlp:"nil"` - Amount2 *hexutil.Big `json:"value2" rlp:"nil"` Payload *hexutil.Bytes `json:"input" gencodec:"required"` V *hexutil.Big `json:"v" gencodec:"required"` R *hexutil.Big `json:"r" gencodec:"required"` @@ -84,12 +78,6 @@ func (t *txdata) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'value' for txdata") } t.Amount = (*big.Int)(dec.Amount) - if dec.CoinID != nil { - t.CoinID = dec.CoinID - } - if dec.Amount2 != nil { - t.Amount2 = (*big.Int)(dec.Amount2) - } if dec.Payload == nil { return errors.New("missing required field 'input' for txdata") } diff --git a/core/types/transaction.go b/core/types/transaction.go index 858b443..d9ada38 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -49,8 +49,6 @@ type txdata struct { GasLimit uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation Amount *big.Int `json:"value" gencodec:"required"` - CoinID *common.Hash `json:"coinid" rlp:"nil"` - Amount2 *big.Int `json:"value2" rlp:"nil"` Payload []byte `json:"input" gencodec:"required"` // Signature values @@ -67,8 +65,6 @@ type txdataMarshaling struct { Price *hexutil.Big GasLimit hexutil.Uint64 Amount *hexutil.Big - CoinID *common.Hash - Amount2 *hexutil.Big Payload hexutil.Bytes V *hexutil.Big R *hexutil.Big @@ -92,8 +88,6 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit Recipient: to, Payload: data, Amount: new(big.Int), - CoinID: nil, - Amount2: new(big.Int), GasLimit: gasLimit, Price: new(big.Int), V: new(big.Int), @@ -110,11 +104,6 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit return &Transaction{data: d} } -func (tx *Transaction) SetMultiCoinValue(coinID *common.Hash, amount *big.Int) { - tx.data.CoinID = coinID - tx.data.Amount2.Set(amount) -} - // ChainId returns which chain id this transaction was signed for (if at all) func (tx *Transaction) ChainId() *big.Int { return deriveChainId(tx.data.V) @@ -183,14 +172,12 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return nil } -func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } -func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } -func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } -func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } -func (tx *Transaction) CoinID() *common.Hash { return tx.data.CoinID } -func (tx *Transaction) Value2() *big.Int { return new(big.Int).Set(tx.data.Amount2) } -func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } -func (tx *Transaction) CheckNonce() bool { return true } +func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } +func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } +func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } +func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } +func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } +func (tx *Transaction) CheckNonce() bool { return true } // To returns the recipient address of the transaction. // It returns nil if the transaction is a contract creation. @@ -237,8 +224,6 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { gasPrice: new(big.Int).Set(tx.data.Price), to: tx.data.Recipient, amount: tx.data.Amount, - coinID: tx.data.CoinID, - amount2: tx.data.Amount2, data: tx.data.Payload, checkNonce: true, } @@ -405,8 +390,6 @@ type Message struct { from common.Address nonce uint64 amount *big.Int - coinID *common.Hash - amount2 *big.Int gasLimit uint64 gasPrice *big.Int data []byte @@ -419,8 +402,6 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b to: to, nonce: nonce, amount: amount, - coinID: nil, - amount2: big.NewInt(0), gasLimit: gasLimit, gasPrice: gasPrice, data: data, @@ -432,8 +413,6 @@ func (m Message) From() common.Address { return m.from } func (m Message) To() *common.Address { return m.to } func (m Message) GasPrice() *big.Int { return m.gasPrice } func (m Message) Value() *big.Int { return m.amount } -func (m Message) CoinID() *common.Hash { return m.coinID } -func (m Message) Value2() *big.Int { return m.amount2 } func (m Message) Gas() uint64 { return m.gasLimit } func (m Message) Nonce() uint64 { return m.nonce } func (m Message) Data() []byte { return m.data } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 3d388d6..e23896a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -26,6 +26,13 @@ import ( "github.com/ava-labs/go-ethereum/log" ) +var ( + BuiltinAddr = common.Address{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } +) + // Config are the configuration options for the Interpreter type Config struct { Debug bool // Enables debugging @@ -131,6 +138,13 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // considered a revert-and-consume-all-gas operation except for // errExecutionReverted which means revert-and-keep-gas-left. func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { + if contract.Address() == BuiltinAddr { + self := AccountRef(contract.Caller()) + if _, ok := contract.caller.(*Contract); ok { + contract = contract.AsDelegate() + } + contract.self = self + } if in.intPool == nil { in.intPool = poolOfIntPools.get() defer func() { diff --git a/eth/api_backend.go b/eth/api_backend.go index 1ca7b94..d4061f8 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -23,7 +23,6 @@ import ( "github.com/ava-labs/coreth/accounts" "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/bloombits" "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/types" @@ -33,6 +32,7 @@ import ( "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/math" + "github.com/ava-labs/go-ethereum/core/bloombits" "github.com/ava-labs/go-ethereum/eth/downloader" "github.com/ava-labs/go-ethereum/ethdb" "github.com/ava-labs/go-ethereum/event" diff --git a/eth/backend.go b/eth/backend.go index 983909c..773f48e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -32,7 +32,6 @@ import ( "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/consensus/ethash" "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/bloombits" "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/core/vm" @@ -45,6 +44,7 @@ import ( "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/hexutil" + "github.com/ava-labs/go-ethereum/core/bloombits" "github.com/ava-labs/go-ethereum/eth/downloader" "github.com/ava-labs/go-ethereum/ethdb" "github.com/ava-labs/go-ethereum/event" diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 3e133d4..6d4a74d 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -22,10 +22,10 @@ import ( "math/big" "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/bloombits" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/core/bloombits" "github.com/ava-labs/go-ethereum/ethdb" "github.com/ava-labs/go-ethereum/event" ) diff --git a/examples/multicoin/main.go b/examples/multicoin/main.go index 403db4d..3b221b1 100644 --- a/examples/multicoin/main.go +++ b/examples/multicoin/main.go @@ -8,6 +8,7 @@ import ( "github.com/ava-labs/coreth/accounts/abi" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/core/vm" "github.com/ava-labs/coreth/eth" "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" @@ -51,18 +52,18 @@ func main() { } // configure the genesis block - genKey, _ := coreth.NewKey(rand.Reader) - bob, _ := coreth.NewKey(rand.Reader) + genesisJSON := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003073ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea2646970667358221220ed2100d6623a884d196eceefabe5e03da4309a2562bb25262f3874f1acb31cd764736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` + mcAbiJSON := `[{"inputs":[],"name":"enableMultiCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"coinid","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"coinid","type":"uint256"},{"internalType":"uint256","name":"amount2","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"}]` + genesisKey := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" - g := new(core.Genesis) - b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003073ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea2646970667358221220ed2100d6623a884d196eceefabe5e03da4309a2562bb25262f3874f1acb31cd764736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` - k := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" - err := json.Unmarshal([]byte(b), g) + bobKey, _ := coreth.NewKey(rand.Reader) + genesisBlock := new(core.Genesis) + err := json.Unmarshal([]byte(genesisJSON), genesisBlock) checkError(err) - config.Genesis = g - hk, _ := crypto.HexToECDSA(k[2:]) - genKey = coreth.NewKeyFromECDSA(hk) + hk, _ := crypto.HexToECDSA(genesisKey[2:]) + genKey := coreth.NewKeyFromECDSA(hk) + config.Genesis = genesisBlock // grab the control of block generation and disable auto uncle config.Miner.ManualMining = true config.Miner.ManualUncle = true @@ -88,17 +89,27 @@ func main() { chain := coreth.NewETHChain(&config, nil, nil, nil) newTxPoolHeadChan := make(chan core.NewTxPoolHeadEvent, 1) log.Info(chain.GetGenesisBlock().Hash().Hex()) + + mcAbi, err := abi.JSON(strings.NewReader(mcAbiJSON)) + checkError(err) + enableCode, err := mcAbi.Pack("enableMultiCoin") + checkError(err) + + abiStr, err := json.Marshal(contract.Info.AbiDefinition) + contractAbi, err := abi.JSON(strings.NewReader(string(abiStr))) + checkError(err) + var contractAddr common.Address - coin0 := common.HexToHash("0x0") postGen := func(block *types.Block) bool { if blockCount == 15 { + coin0 := common.HexToHash("0x0") state, err := chain.CurrentState() checkError(err) log.Info(fmt.Sprintf("genesis balance = %s", state.GetBalance(genKey.Address))) - log.Info(fmt.Sprintf("genesis balance2 = %s", state.GetBalanceMultiCoin(genKey.Address, coin0))) - log.Info(fmt.Sprintf("contract balance2 = %s", state.GetBalanceMultiCoin(contractAddr, coin0))) - log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bob.Address))) - log.Info(fmt.Sprintf("bob's balance2 = %s", state.GetBalanceMultiCoin(bob.Address, coin0))) + log.Info(fmt.Sprintf("genesis mcbalance(0) = %s", state.GetBalanceMultiCoin(genKey.Address, coin0))) + log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bobKey.Address))) + log.Info(fmt.Sprintf("bob's mcbalance(0) = %s", state.GetBalanceMultiCoin(bobKey.Address, coin0))) + log.Info(fmt.Sprintf("contract mcbalance(0) = %s", state.GetBalanceMultiCoin(contractAddr, coin0))) log.Info(fmt.Sprintf("state = %s", state.Dump(true, false, true))) return true } @@ -111,53 +122,54 @@ func main() { log.Info(fmt.Sprintf("contract addr = %s", contractAddr.String())) go func() { - tx := types.NewTransaction(nonce, bob.Address, big.NewInt(300000000000000000), uint64(gasLimit), gasPrice, nil) + // give Bob some initial balance + tx := types.NewTransaction(nonce, bobKey.Address, big.NewInt(300000000000000000), uint64(gasLimit), gasPrice, nil) signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ time.Sleep(20 * time.Millisecond) - // self-loop tx to enable MC - tx = types.NewTransaction(0, bob.Address, big.NewInt(1), uint64(gasLimit), gasPrice, nil) - tx.SetMultiCoinValue(&coin0, big.NewInt(0)) - signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), bob.PrivateKey) + // enable MC for Bob + tx = types.NewTransaction(0, vm.BuiltinAddr, big.NewInt(0), uint64(gasLimit), gasPrice, enableCode) + signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), bobKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) + time.Sleep(20 * time.Millisecond) - var code []byte - var a abi.ABI - abiStr, err := json.Marshal(contract.Info.AbiDefinition) - a, err = abi.JSON(strings.NewReader(string(abiStr))) + bobTransferInput, err := mcAbi.Pack("transfer", bobKey.Address, big.NewInt(0), big.NewInt(0), big.NewInt(100000000000000000)) checkError(err) - code, err = a.Pack("deposit") + contractTransferInput, err := mcAbi.Pack("transfer", contractAddr, big.NewInt(0), big.NewInt(0), big.NewInt(100000000000000000)) checkError(err) for i := 0; i < 5; i++ { - tx := types.NewTransaction(nonce, bob.Address, big.NewInt(0), uint64(gasLimit), gasPrice, nil) - tx.SetMultiCoinValue(&coin0, big.NewInt(100000000000000000)) + // transfer some coin0 balance to Bob + tx := types.NewTransaction(nonce, vm.BuiltinAddr, big.NewInt(0), uint64(gasLimit), gasPrice, bobTransferInput) signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ - tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) - tx.SetMultiCoinValue(&coin0, big.NewInt(100000000000000000)) + // transfer some coin0 balance to the contract + tx = types.NewTransaction(nonce, vm.BuiltinAddr, big.NewInt(0), uint64(gasLimit), gasPrice, contractTransferInput) signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ } - code, err = a.Pack("withdraw", big.NewInt(0), big.NewInt(0), big.NewInt(10000000000000000)) - tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) + + // test contract methods + + input, err := contractAbi.Pack("withdraw", big.NewInt(0), big.NewInt(0), big.NewInt(10000000000000000)) + tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, input) signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) nonce++ - code, err = a.Pack("updateBalance", big.NewInt(0)) - tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, code) + input, err = contractAbi.Pack("updateBalance", big.NewInt(0)) + tx = types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, input) signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) chain.AddRemoteTxs([]*types.Transaction{signedTx}) @@ -191,6 +203,7 @@ func main() { chain.GetTxPool().SubscribeNewHeadEvent(newTxPoolHeadChan) chain.Start() code := common.Hex2Bytes(contract.Code[2:]) + tx := types.NewContractCreation(nonce, big.NewInt(0), uint64(gasLimit), gasPrice, code) signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) checkError(err) diff --git a/examples/multicoin/mc_test.sol b/examples/multicoin/mc_test.sol index bfd42a5..ec07ee6 100644 --- a/examples/multicoin/mc_test.sol +++ b/examples/multicoin/mc_test.sol @@ -5,23 +5,23 @@ contract MCTest { uint256 balance; constructor() public { // enable multi-coin functionality (it is disabled by default) - (bool success,) = MultiCoin.delegatecall(abi.encodeWithSignature("enableMultiCoin()")); + (bool success,) = MultiCoin.call(abi.encodeWithSignature("enableMultiCoin()")); require(success); } function updateBalance(uint256 coinid) public { - (bool success, bytes memory data) = MultiCoin.delegatecall(abi.encodeWithSignature("getBalance(uint256)", coinid)); + (bool success, bytes memory data) = MultiCoin.call(abi.encodeWithSignature("getBalance(uint256)", coinid)); require(success); balance = abi.decode(data, (uint256)); } - function deposit() public payable {} - function withdraw(uint256 amount, uint256 coinid, uint256 amount2) public { - (bool success,) = MultiCoin.delegatecall( + (bool success,) = MultiCoin.call( abi.encodeWithSignature("transfer(address,uint256,uint256,uint256)", msg.sender, amount, coinid, amount2)); require(success); } + + receive() external payable {} } diff --git a/go.mod b/go.mod index 86b7bfd..ff6b943 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/ava-labs/gecko v0.5.7 github.com/ava-labs/go-ethereum v1.9.3 + github.com/cespare/cp v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.7.1 github.com/edsrzf/mmap-go v1.0.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ef390f8 --- /dev/null +++ b/go.sum @@ -0,0 +1,337 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AppsFlyer/go-sundheit v0.2.0/go.mod h1:rCRkVTMQo7/krF7xQ9X0XEF1an68viFR6/Gy02q+4ds= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= +github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20200520141224-0f14e646773f h1:uM6lu1fpmCwf54zb6Ckkvphioq8MLlyFb/TlTgPpCKc= +github.com/aristanetworks/goarista v0.0.0-20200520141224-0f14e646773f/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/ava-labs/coreth v0.2.5/go.mod h1:pGolKipwq5vGIY2IBBcBkMYrqniXMsS5SBn+BBi4+Js= +github.com/ava-labs/gecko v0.5.7/go.mod h1:EdaEuYNRZ3UB+Efr1Nn+DsM3EzdUtg641ZF6FUBCACs= +github.com/ava-labs/go-ethereum v1.9.3 h1:GmnMZ/dlvVAPFmWBzEpRJX49pUAymPfoASLNRJqR0AY= +github.com/ava-labs/go-ethereum v1.9.3/go.mod h1:a+agc6fXfZFsPZCylA3ry4Y8CLCqLKg3Rc23NXZ9aw8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= +github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1 v1.0.3/go.mod h1:eCL8H4MYYjRvsw2TuANvEOcVMFbmi9rt/6hJUWU5wlU= +github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0/go.mod h1:3s92l0paYkZoIHuj4X93Teg/HB7eGM9x/zokGw+u4mY= +github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0-20200526030155-0c6c7ca85d3b/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo= +github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gdamore/optopia v0.2.0/go.mod h1:YKYEwo5C1Pa617H7NlPcmQXl+vG6YnSSNB44n8dNL0Q= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ= +github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= +github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= +github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 h1:Oo2KZNP70KE0+IUJSidPj/BFS/RXNHmKIJOdckzml2E= +github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +nanomsg.org/go/mangos/v2 v2.0.8/go.mod h1:gngxudWUZkxqHN+8n/2y9gWZPcwmSbliFYJsYG8mbKs= diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 107af3a..fb38034 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -23,13 +23,13 @@ import ( "github.com/ava-labs/coreth/accounts" "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/bloombits" "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/core/vm" "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/core/bloombits" "github.com/ava-labs/go-ethereum/eth/downloader" "github.com/ava-labs/go-ethereum/ethdb" "github.com/ava-labs/go-ethereum/event" -- cgit v1.2.3-70-g09d2