mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 05:41:35 +00:00
Merge pull request #452 from gzliudan/new-vm
preparation for solidity v0.8.23 upgrade
This commit is contained in:
commit
df2384eb9a
34 changed files with 708 additions and 1259 deletions
|
|
@ -56,7 +56,12 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
|
|||
log.Memory = memory.Data()
|
||||
}
|
||||
if !l.cfg.DisableStack {
|
||||
log.Stack = stack.Data()
|
||||
//TODO(@holiman) improve this
|
||||
logstack := make([]*big.Int, len(stack.Data()))
|
||||
for i, item := range stack.Data() {
|
||||
logstack[i] = item.ToBig()
|
||||
}
|
||||
log.Stack = logstack
|
||||
}
|
||||
return l.encoder.Encode(log)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,9 +306,6 @@ func (self *stateObject) setBalance(amount *big.Int) {
|
|||
}
|
||||
}
|
||||
|
||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||
func (c *stateObject) ReturnGas(gas *big.Int) {}
|
||||
|
||||
func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
|
||||
stateObject := newObject(db, self.address, self.data, onDirty)
|
||||
if self.trie != nil {
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package vm
|
||||
|
||||
const (
|
||||
set2BitsMask = uint16(0b1100_0000_0000_0000)
|
||||
set3BitsMask = uint16(0b1110_0000_0000_0000)
|
||||
set4BitsMask = uint16(0b1111_0000_0000_0000)
|
||||
set5BitsMask = uint16(0b1111_1000_0000_0000)
|
||||
set6BitsMask = uint16(0b1111_1100_0000_0000)
|
||||
set7BitsMask = uint16(0b1111_1110_0000_0000)
|
||||
set2BitsMask = uint16(0b11)
|
||||
set3BitsMask = uint16(0b111)
|
||||
set4BitsMask = uint16(0b1111)
|
||||
set5BitsMask = uint16(0b1_1111)
|
||||
set6BitsMask = uint16(0b11_1111)
|
||||
set7BitsMask = uint16(0b111_1111)
|
||||
)
|
||||
|
||||
// bitvec is a bit vector which maps bytes in a program.
|
||||
|
|
@ -30,32 +30,26 @@ const (
|
|||
// it's data (i.e. argument of PUSHxx).
|
||||
type bitvec []byte
|
||||
|
||||
var lookup = [8]byte{
|
||||
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1,
|
||||
}
|
||||
|
||||
func (bits bitvec) set1(pos uint64) {
|
||||
bits[pos/8] |= lookup[pos%8]
|
||||
bits[pos/8] |= 1 << (pos % 8)
|
||||
}
|
||||
|
||||
func (bits bitvec) setN(flag uint16, pos uint64) {
|
||||
a := flag >> (pos % 8)
|
||||
bits[pos/8] |= byte(a >> 8)
|
||||
if b := byte(a); b != 0 {
|
||||
// If the bit-setting affects the neighbouring byte, we can assign - no need to OR it,
|
||||
// since it's the first write to that byte
|
||||
a := flag << (pos % 8)
|
||||
bits[pos/8] |= byte(a)
|
||||
if b := byte(a >> 8); b != 0 {
|
||||
bits[pos/8+1] = b
|
||||
}
|
||||
}
|
||||
|
||||
func (bits bitvec) set8(pos uint64) {
|
||||
a := byte(0xFF >> (pos % 8))
|
||||
a := byte(0xFF << (pos % 8))
|
||||
bits[pos/8] |= a
|
||||
bits[pos/8+1] = ^a
|
||||
}
|
||||
|
||||
func (bits bitvec) set16(pos uint64) {
|
||||
a := byte(0xFF >> (pos % 8))
|
||||
a := byte(0xFF << (pos % 8))
|
||||
bits[pos/8] |= a
|
||||
bits[pos/8+1] = 0xFF
|
||||
bits[pos/8+2] = ^a
|
||||
|
|
@ -63,7 +57,7 @@ func (bits bitvec) set16(pos uint64) {
|
|||
|
||||
// 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
|
||||
return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
|
||||
}
|
||||
|
||||
// codeBitmap collects data locations in code.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
|
|
@ -28,24 +29,27 @@ func TestJumpDestAnalysis(t *testing.T) {
|
|||
exp byte
|
||||
which int
|
||||
}{
|
||||
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0x40, 0},
|
||||
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0x50, 0},
|
||||
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, 0x7F, 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 1},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0x03, 0},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x74, 0},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x3F, 0},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xC0, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x7F, 0},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xFF, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 2},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0x7f, 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0xA0, 1},
|
||||
{[]byte{byte(PUSH32)}, 0x7F, 0},
|
||||
{[]byte{byte(PUSH32)}, 0xFF, 1},
|
||||
{[]byte{byte(PUSH32)}, 0xFF, 2},
|
||||
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
|
||||
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0},
|
||||
{[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0},
|
||||
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 1},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 2},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 3},
|
||||
{[]byte{byte(PUSH32)}, 0b0000_0001, 4},
|
||||
}
|
||||
for i, test := range tests {
|
||||
ret := codeBitmap(test.code)
|
||||
|
|
@ -55,9 +59,12 @@ func TestJumpDestAnalysis(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const analysisCodeSize = 1200 * 1024
|
||||
|
||||
func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
||||
// 1.4 ms
|
||||
code := make([]byte, 1200000)
|
||||
code := make([]byte, analysisCodeSize)
|
||||
bench.SetBytes(analysisCodeSize)
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
codeBitmap(code)
|
||||
|
|
@ -66,7 +73,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
|||
}
|
||||
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
||||
// 4 ms
|
||||
code := make([]byte, 1200000)
|
||||
code := make([]byte, analysisCodeSize)
|
||||
bench.SetBytes(analysisCodeSize)
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
crypto.Keccak256Hash(code)
|
||||
|
|
@ -77,13 +85,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
|||
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
|
||||
var op OpCode
|
||||
bencher := func(b *testing.B) {
|
||||
code := make([]byte, 32*b.N)
|
||||
code := make([]byte, analysisCodeSize)
|
||||
b.SetBytes(analysisCodeSize)
|
||||
for i := range code {
|
||||
code[i] = byte(op)
|
||||
}
|
||||
bits := make(bitvec, len(code)/8+1+4)
|
||||
b.ResetTimer()
|
||||
codeBitmapInternal(code, bits)
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range bits {
|
||||
bits[j] = 0
|
||||
}
|
||||
codeBitmapInternal(code, bits)
|
||||
}
|
||||
}
|
||||
for op = PUSH1; op <= PUSH32; op++ {
|
||||
bench.Run(op.String(), bencher)
|
||||
|
|
|
|||
|
|
@ -17,15 +17,14 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// calcMemSize64 calculates the required memory size, and returns
|
||||
// the size and whether the result overflowed uint64
|
||||
func calcMemSize64(off, l *big.Int) (uint64, bool) {
|
||||
func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
|
||||
if !l.IsUint64() {
|
||||
return 0, true
|
||||
}
|
||||
|
|
@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
|
|||
// 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) {
|
||||
func calcMemSize64WithUint(off *uint256.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() {
|
||||
offset64, overflow := off.Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, true
|
||||
}
|
||||
offset64 := off.Uint64()
|
||||
val := offset64 + length64
|
||||
// if value < either of it's parts, then it overflowed
|
||||
return val, val < offset64
|
||||
|
|
@ -64,22 +63,6 @@ func getData(data []byte, start uint64, size uint64) []byte {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// ContractRef is a reference to the contract's backing object
|
||||
|
|
@ -81,11 +82,11 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *Contract) validJumpdest(dest *big.Int) bool {
|
||||
udest := dest.Uint64()
|
||||
func (c *Contract) validJumpdest(dest *uint256.Int) bool {
|
||||
udest, overflow := dest.Uint64WithOverflow()
|
||||
// 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)) {
|
||||
if overflow || udest >= uint64(len(c.Code)) {
|
||||
return false
|
||||
}
|
||||
// Only JUMPDESTs allowed for destinations
|
||||
|
|
@ -131,16 +132,11 @@ func (c *Contract) AsDelegate() *Contract {
|
|||
|
||||
// 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 OpCode(c.Code[n])
|
||||
}
|
||||
|
||||
return 0
|
||||
return STOP
|
||||
}
|
||||
|
||||
// Caller returns the caller of the contract.
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
|
|||
// Parse the input into the Blake2b call parameters
|
||||
var (
|
||||
rounds = binary.BigEndian.Uint32(input[0:4])
|
||||
final = (input[212] == blake2FFinalBlockBytes)
|
||||
final = input[212] == blake2FFinalBlockBytes
|
||||
|
||||
h [8]uint64
|
||||
m [16]uint64
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// EnableEIP enables the given EIP on the config.
|
||||
|
|
@ -51,17 +52,16 @@ func enable1884(jt *JumpTable) {
|
|||
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
|
||||
|
||||
// New opcode
|
||||
jt[SELFBALANCE] = operation{
|
||||
jt[SELFBALANCE] = &operation{
|
||||
execute: opSelfBalance,
|
||||
constantGas: GasFastStep,
|
||||
minStack: minStack(0, 1),
|
||||
maxStack: maxStack(0, 1),
|
||||
valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
|
||||
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
|
||||
callContext.stack.push(balance)
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -70,18 +70,17 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
|
|||
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
|
||||
func enable1344(jt *JumpTable) {
|
||||
// New opcode
|
||||
jt[CHAINID] = operation{
|
||||
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, callContext *callCtx) ([]byte, error) {
|
||||
chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainId)
|
||||
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainId)
|
||||
callContext.stack.push(chainId)
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ var (
|
|||
ErrWriteProtection = errors.New("write protection")
|
||||
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
||||
ErrGasUintOverflow = errors.New("gas uint64 overflow")
|
||||
|
||||
// errStopToken is an internal token indicating interpreter loop termination,
|
||||
// never returned to outside callers.
|
||||
errStopToken = errors.New("stop token")
|
||||
)
|
||||
|
||||
// ErrStackUnderflow wraps an evm error when the items on the stack less
|
||||
|
|
|
|||
|
|
@ -189,9 +189,6 @@ func (evm *EVM) Interpreter() Interpreter {
|
|||
// 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
|
||||
|
|
@ -263,9 +260,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
// 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
|
||||
|
|
@ -302,9 +296,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
// 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
|
||||
|
|
@ -332,9 +323,6 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
// 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
|
||||
|
|
@ -353,7 +341,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// 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)
|
||||
evm.StateDB.AddBalance(addr, big.NewInt(0))
|
||||
}
|
||||
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
|
|
@ -412,10 +400,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
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)
|
||||
}
|
||||
|
|
@ -423,13 +407,16 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
|
||||
ret, err := run(evm, contract, nil, false)
|
||||
|
||||
// check whether the max code size has been exceeded
|
||||
maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
|
||||
// Check whether the max code size has been exceeded, assign err if the case.
|
||||
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
||||
err = ErrMaxCodeSizeExceeded
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if err == nil {
|
||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||
if contract.UseGas(createDataGas) {
|
||||
evm.StateDB.SetCode(address, ret)
|
||||
|
|
@ -441,21 +428,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
// 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)) {
|
||||
if 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.
|
||||
|
|
@ -466,7 +449,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
|
||||
// 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:]
|
||||
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(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}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// Gas costs
|
||||
|
|
@ -34,7 +34,7 @@ const (
|
|||
//
|
||||
// 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) {
|
||||
func callGas(isEip150 bool, availableGas, base uint64, callCost *uint256.Int) (uint64, error) {
|
||||
if isEip150 {
|
||||
availableGas = availableGas - base
|
||||
gas := availableGas - availableGas/64
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
|||
// as argument:
|
||||
// CALLDATACOPY (stack position 2)
|
||||
// CODECOPY (stack position 2)
|
||||
// EXTCODECOPY (stack poition 3)
|
||||
// EXTCODECOPY (stack position 3)
|
||||
// RETURNDATACOPY (stack position 2)
|
||||
func memoryCopierGas(stackpos int) gasFunc {
|
||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
|
|
@ -71,7 +71,7 @@ func memoryCopierGas(stackpos int) gasFunc {
|
|||
return 0, err
|
||||
}
|
||||
// And gas for copying data, charged per word at param.CopyGas
|
||||
words, overflow := bigUint64(stack.Back(stackpos))
|
||||
words, overflow := stack.Back(stackpos).Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ var (
|
|||
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))
|
||||
current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
|
||||
)
|
||||
// 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)
|
||||
|
|
@ -132,11 +132,11 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
|||
// 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)
|
||||
value := common.Hash(y.Bytes32())
|
||||
if current == value { // noop (1)
|
||||
return params.NetSstoreNoopGas, nil
|
||||
}
|
||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
|
||||
if original == current {
|
||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||
return params.NetSstoreInitGas, nil
|
||||
|
|
@ -164,18 +164,18 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
|||
}
|
||||
|
||||
// 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.
|
||||
// 1. If current value equals new value (this is a no-op), SLOAD_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.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted.
|
||||
// 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter.
|
||||
// 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_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.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter.
|
||||
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE 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.
|
||||
// 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
|
||||
// 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS 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 {
|
||||
|
|
@ -184,43 +184,43 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
|||
// 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))
|
||||
current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
|
||||
)
|
||||
value := common.BigToHash(y)
|
||||
value := common.Hash(y.Bytes32())
|
||||
|
||||
if current == value { // noop (1)
|
||||
return params.SstoreNoopGasEIP2200, nil
|
||||
return params.SloadGasEIP2200, nil
|
||||
}
|
||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
|
||||
if original == current {
|
||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||
return params.SstoreInitGasEIP2200, nil
|
||||
return params.SstoreSetGasEIP2200, nil
|
||||
}
|
||||
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
|
||||
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
|
||||
}
|
||||
return params.SstoreCleanGasEIP2200, nil // write existing slot (2.1.2)
|
||||
return params.SstoreResetGasEIP2200, 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)
|
||||
evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200)
|
||||
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
|
||||
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
|
||||
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200)
|
||||
}
|
||||
}
|
||||
if original == value {
|
||||
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
||||
evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200)
|
||||
evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
|
||||
} else { // reset to original existing slot (2.2.2.2)
|
||||
evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200)
|
||||
evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
|
||||
}
|
||||
}
|
||||
return params.SstoreDirtyGasEIP2200, nil // dirty update (2.2)
|
||||
return params.SloadGasEIP2200, 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))
|
||||
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
@ -248,16 +248,16 @@ func makeGasLog(n uint64) gasFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
func gasKeccak256(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))
|
||||
wordGas, overflow := stack.Back(1).Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
||||
|
|
@ -287,11 +287,11 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
wordGas, overflow := bigUint64(stack.Back(2))
|
||||
wordGas, overflow := stack.Back(2).Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
|
||||
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
||||
|
|
@ -329,8 +329,8 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
|
|||
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))
|
||||
transfersValue = !stack.Back(2).IsZero()
|
||||
address = common.Address(stack.Back(1).Bytes20())
|
||||
)
|
||||
if evm.chainRules.IsEIP158 {
|
||||
if transfersValue && evm.StateDB.Empty(address) {
|
||||
|
|
@ -423,7 +423,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
|||
// EIP150 homestead gas reprice fork:
|
||||
if evm.chainRules.IsEIP150 {
|
||||
gas = params.SelfdestructGasEIP150
|
||||
var address = common.BigToAddress(stack.Back(0))
|
||||
var address = common.Address(stack.Back(0).Bytes20())
|
||||
|
||||
if evm.chainRules.IsEIP158 {
|
||||
// if empty and transfers value
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -21,14 +21,13 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type TwoOperandTestcase struct {
|
||||
|
|
@ -42,6 +41,7 @@ type twoOperandParams struct {
|
|||
y string
|
||||
}
|
||||
|
||||
var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
var commonParams []*twoOperandParams
|
||||
var twoOpMethods map[string]executionFunc
|
||||
|
||||
|
|
@ -91,31 +91,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// getResult is a convenience function to generate the expected values
|
||||
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
pc = uint64(0)
|
||||
interpreter = env.interpreter.(*EVMInterpreter)
|
||||
)
|
||||
interpreter.intPool = poolOfIntPools.get()
|
||||
result := make([]TwoOperandTestcase, len(args))
|
||||
for i, param := range args {
|
||||
x := new(big.Int).SetBytes(common.Hex2Bytes(param.x))
|
||||
y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
|
||||
stack.push(x)
|
||||
stack.push(y)
|
||||
_, err := opFn(&pc, interpreter, &callCtx{nil, stack, nil})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
actual := stack.pop()
|
||||
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
|
||||
|
||||
var (
|
||||
|
|
@ -124,42 +99,23 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
|||
pc = uint64(0)
|
||||
evmInterpreter = env.interpreter.(*EVMInterpreter)
|
||||
)
|
||||
// Stuff a couple of nonzero bigints into pool, to ensure that ops do not rely on pooled integers to be zero
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
||||
|
||||
for i, test := range tests {
|
||||
x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
|
||||
y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
|
||||
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X))
|
||||
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y))
|
||||
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||
stack.push(x)
|
||||
stack.push(y)
|
||||
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
||||
if len(stack.data) != 1 {
|
||||
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
|
||||
}
|
||||
actual := stack.pop()
|
||||
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
|
||||
}
|
||||
// Check pool usage
|
||||
// 1.pool is not allowed to contain anything on the stack
|
||||
// 2.pool is not allowed to contain the same pointers twice
|
||||
if evmInterpreter.intPool.pool.len() > 0 {
|
||||
|
||||
poolvals := make(map[*big.Int]struct{})
|
||||
poolvals[actual] = struct{}{}
|
||||
|
||||
for evmInterpreter.intPool.pool.len() > 0 {
|
||||
key := evmInterpreter.intPool.get()
|
||||
if _, exist := poolvals[key]; exist {
|
||||
t.Errorf("Testcase %v %d, pool contains double-entry", name, i)
|
||||
}
|
||||
poolvals[key] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func TestByteOp(t *testing.T) {
|
||||
|
|
@ -235,6 +191,68 @@ func TestSAR(t *testing.T) {
|
|||
testTwoOperandOp(t, tests, opSAR, "sar")
|
||||
}
|
||||
|
||||
func TestAddMod(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
pc = uint64(0)
|
||||
)
|
||||
tests := []struct {
|
||||
x string
|
||||
y string
|
||||
z string
|
||||
expected string
|
||||
}{
|
||||
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
},
|
||||
}
|
||||
// x + y = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
|
||||
// in 256 bit repr, fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
|
||||
|
||||
for i, test := range tests {
|
||||
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.x))
|
||||
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.y))
|
||||
z := new(uint256.Int).SetBytes(common.Hex2Bytes(test.z))
|
||||
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.expected))
|
||||
stack.push(z)
|
||||
stack.push(y)
|
||||
stack.push(x)
|
||||
opAddmod(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
||||
actual := stack.pop()
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getResult is a convenience function to generate the expected values
|
||||
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
pc = uint64(0)
|
||||
interpreter = env.interpreter.(*EVMInterpreter)
|
||||
)
|
||||
result := make([]TwoOperandTestcase, len(args))
|
||||
for i, param := range args {
|
||||
x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x))
|
||||
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
||||
stack.push(x)
|
||||
stack.push(y)
|
||||
_, err := opFn(&pc, interpreter, &callCtx{nil, stack, nil})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
actual := stack.pop()
|
||||
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// utility function to fill the json-file with testcases
|
||||
// Enable this test to generate the 'testcases_xx.json' files
|
||||
func TestWriteExpectedValues(t *testing.T) {
|
||||
|
|
@ -276,7 +294,6 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
|||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
// convert args
|
||||
byteArgs := make([][]byte, len(args))
|
||||
for i, arg := range args {
|
||||
|
|
@ -286,13 +303,13 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
|||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
for _, arg := range byteArgs {
|
||||
a := new(big.Int).SetBytes(arg)
|
||||
a := new(uint256.Int)
|
||||
a.SetBytes(arg)
|
||||
stack.push(a)
|
||||
}
|
||||
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
||||
stack.pop()
|
||||
}
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func BenchmarkOpAdd64(b *testing.B) {
|
||||
|
|
@ -338,8 +355,8 @@ func BenchmarkOpSub256(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkOpMul(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opMul, x, y)
|
||||
}
|
||||
|
|
@ -370,64 +387,64 @@ func BenchmarkOpSdiv(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkOpMod(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opMod, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpSmod(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opSmod, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpExp(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opExp, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpSignExtend(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opSignExtend, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpLt(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opLt, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpGt(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opGt, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpSlt(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opSlt, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpSgt(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opSgt, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpEq(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opEq, x, y)
|
||||
}
|
||||
|
|
@ -437,45 +454,45 @@ func BenchmarkOpEq2(b *testing.B) {
|
|||
opBenchmark(b, opEq, x, y)
|
||||
}
|
||||
func BenchmarkOpAnd(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opAnd, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpOr(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opOr, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpXor(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opXor, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpByte(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
|
||||
opBenchmark(b, opByte, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpAddmod(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
z := alphabetSoup
|
||||
|
||||
opBenchmark(b, opAddmod, x, y, z)
|
||||
}
|
||||
|
||||
func BenchmarkOpMulmod(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
x := alphabetSoup
|
||||
y := alphabetSoup
|
||||
z := alphabetSoup
|
||||
|
||||
opBenchmark(b, opMulmod, x, y, z)
|
||||
}
|
||||
|
|
@ -512,21 +529,21 @@ func TestOpMstore(t *testing.T) {
|
|||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
|
||||
stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
|
||||
stack.push(new(uint256.Int))
|
||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||
}
|
||||
stack.pushN(big.NewInt(0x1), big.NewInt(0))
|
||||
stack.push(new(uint256.Int).SetUint64(0x1))
|
||||
stack.push(new(uint256.Int))
|
||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||
t.Fatalf("Mstore failed to overwrite previous value")
|
||||
}
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func BenchmarkOpMstore(bench *testing.B) {
|
||||
|
|
@ -538,21 +555,20 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
memStart := big.NewInt(0)
|
||||
value := big.NewInt(0x1337)
|
||||
memStart := new(uint256.Int)
|
||||
value := new(uint256.Int).SetUint64(0x1337)
|
||||
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
stack.pushN(value, memStart)
|
||||
stack.push(value)
|
||||
stack.push(memStart)
|
||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||
}
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func BenchmarkOpSHA3(bench *testing.B) {
|
||||
func BenchmarkOpKeccak256(bench *testing.B) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
|
|
@ -560,17 +576,16 @@ func BenchmarkOpSHA3(bench *testing.B) {
|
|||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
mem.Resize(32)
|
||||
pc := uint64(0)
|
||||
start := big.NewInt(0)
|
||||
start := new(uint256.Int)
|
||||
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
stack.pushN(big.NewInt(32), start)
|
||||
opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||
stack.push(uint256.NewInt(32))
|
||||
stack.push(start)
|
||||
opKeccak256(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||
}
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func TestCreate2Addreses(t *testing.T) {
|
||||
|
|
@ -644,6 +659,5 @@ func TestCreate2Addreses(t *testing.T) {
|
|||
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
|
||||
t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build !VERIFY_EVM_INTEGER_POOL
|
||||
|
||||
package vm
|
||||
|
||||
const verifyPool = false
|
||||
|
||||
func verifyIntegerPool(ip *intPool) {}
|
||||
|
|
@ -18,7 +18,6 @@ package vm
|
|||
|
||||
import (
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
|
|
@ -29,10 +28,9 @@ import (
|
|||
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
|
||||
JumpTable *JumpTable // EVM instruction table, automatically populated if unset
|
||||
|
||||
EWASMInterpreter string // External EWASM interpreter options
|
||||
EVMInterpreter string // External EVM interpreter options
|
||||
|
|
@ -83,8 +81,6 @@ 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
|
||||
|
||||
|
|
@ -94,35 +90,36 @@ type EVMInterpreter struct {
|
|||
|
||||
// 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
|
||||
// If jump table was not initialised we set the default one.
|
||||
if cfg.JumpTable == nil {
|
||||
switch {
|
||||
case evm.chainRules.IsIstanbul:
|
||||
jt = istanbulInstructionSet
|
||||
cfg.JumpTable = &istanbulInstructionSet
|
||||
case evm.chainRules.IsConstantinople:
|
||||
jt = constantinopleInstructionSet
|
||||
cfg.JumpTable = &constantinopleInstructionSet
|
||||
case evm.chainRules.IsByzantium:
|
||||
jt = byzantiumInstructionSet
|
||||
cfg.JumpTable = &byzantiumInstructionSet
|
||||
case evm.chainRules.IsEIP158:
|
||||
jt = spuriousDragonInstructionSet
|
||||
cfg.JumpTable = &spuriousDragonInstructionSet
|
||||
case evm.chainRules.IsEIP150:
|
||||
jt = tangerineWhistleInstructionSet
|
||||
cfg.JumpTable = &tangerineWhistleInstructionSet
|
||||
case evm.chainRules.IsHomestead:
|
||||
jt = homesteadInstructionSet
|
||||
cfg.JumpTable = &homesteadInstructionSet
|
||||
default:
|
||||
jt = frontierInstructionSet
|
||||
cfg.JumpTable = &frontierInstructionSet
|
||||
}
|
||||
for i, eip := range cfg.ExtraEips {
|
||||
if err := EnableEIP(eip, &jt); err != nil {
|
||||
var extraEips []int
|
||||
for _, eip := range cfg.ExtraEips {
|
||||
copy := *cfg.JumpTable
|
||||
if err := EnableEIP(eip, ©); 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)
|
||||
} else {
|
||||
extraEips = append(extraEips, eip)
|
||||
}
|
||||
cfg.JumpTable = ©
|
||||
}
|
||||
cfg.JumpTable = jt
|
||||
cfg.ExtraEips = extraEips
|
||||
}
|
||||
|
||||
return &EVMInterpreter{
|
||||
|
|
@ -138,20 +135,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 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.
|
||||
// This also makes sure that the readOnly flag isn't removed for child calls.
|
||||
if readOnly && !in.readOnly {
|
||||
in.readOnly = true
|
||||
defer func() { in.readOnly = false }()
|
||||
|
|
@ -188,9 +178,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
)
|
||||
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 {
|
||||
|
|
@ -206,12 +193,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
// 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.
|
||||
steps := 0
|
||||
for {
|
||||
steps++
|
||||
if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 {
|
||||
break
|
||||
}
|
||||
if in.cfg.Debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
|
|
@ -221,26 +203,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
// enough stack items available to perform the operation.
|
||||
op = contract.GetOp(pc)
|
||||
operation := in.cfg.JumpTable[op]
|
||||
if !operation.valid {
|
||||
return nil, &ErrInvalidOpCode{opcode: op}
|
||||
}
|
||||
// Validate stack
|
||||
if sLen := stack.len(); sLen < operation.minStack {
|
||||
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
||||
} else if sLen > operation.maxStack {
|
||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: 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) {
|
||||
|
|
@ -285,29 +253,17 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
|
||||
// execute the operation
|
||||
res, err = operation.execute(&pc, in, callContext)
|
||||
// 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:
|
||||
log.Debug("ErrExecutionReverted", "pc", pc, "reverts", operation.reverts, "err", err)
|
||||
return res, ErrExecutionReverted
|
||||
case operation.halts:
|
||||
return res, nil
|
||||
case !operation.jumps:
|
||||
pc++
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
pc++
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
if err == errStopToken {
|
||||
err = nil // clear stop token error
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// CanRun tells if the contract, passed as an argument, can be
|
||||
|
|
|
|||
|
|
@ -1,117 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// putOne 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!
|
||||
// As opposed to 'put' with variadic args, this method becomes inlined by the
|
||||
// go compiler
|
||||
func (p *intPool) putOne(i *big.Int) {
|
||||
if len(p.pool.data) > poolLimit {
|
||||
return
|
||||
}
|
||||
p.pool.push(i)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIntPoolPoolGet(t *testing.T) {
|
||||
poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
|
||||
|
||||
nip := poolOfIntPools.get()
|
||||
if nip == nil {
|
||||
t.Fatalf("Invalid pool allocation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntPoolPoolPut(t *testing.T) {
|
||||
poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
|
||||
|
||||
nip := poolOfIntPools.get()
|
||||
if len(poolOfIntPools.pools) != 0 {
|
||||
t.Fatalf("Pool got added to list when none should have been")
|
||||
}
|
||||
|
||||
poolOfIntPools.put(nip)
|
||||
if len(poolOfIntPools.pools) == 0 {
|
||||
t.Fatalf("Pool did not get added to list when one should have been")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntPoolPoolReUse(t *testing.T) {
|
||||
poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
|
||||
nip := poolOfIntPools.get()
|
||||
poolOfIntPools.put(nip)
|
||||
poolOfIntPools.get()
|
||||
|
||||
if len(poolOfIntPools.pools) != 0 {
|
||||
t.Fatalf("Invalid number of pools. Got %d, expected %d", len(poolOfIntPools.pools), 0)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -156,8 +156,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
|||
// 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])
|
||||
value = common.Hash(stack.data[stack.len()-2].Bytes32())
|
||||
address = common.Hash(stack.data[stack.len()-1].Bytes32())
|
||||
)
|
||||
l.changedValues[contract.Address()][address] = value
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
|||
if !l.cfg.DisableStack {
|
||||
stck = make([]*big.Int, len(stack.Data()))
|
||||
for i, item := range stack.Data() {
|
||||
stck[i] = new(big.Int).Set(item)
|
||||
stck[i] = new(big.Int).Set(item.ToBig())
|
||||
}
|
||||
}
|
||||
// Copy a snapshot of the current storage to a new container
|
||||
|
|
|
|||
|
|
@ -62,14 +62,19 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
|
|||
log.Memory = memory.Data()
|
||||
}
|
||||
if !l.cfg.DisableStack {
|
||||
log.Stack = stack.Data()
|
||||
//TODO(@holiman) improve this
|
||||
logstack := make([]*big.Int, len(stack.Data()))
|
||||
for i, item := range stack.Data() {
|
||||
logstack[i] = item.ToBig()
|
||||
}
|
||||
log.Stack = logstack
|
||||
}
|
||||
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
|
||||
return l.CaptureState(env, pc, op, gas, cost, memory, stack, contract, depth, err)
|
||||
}
|
||||
|
||||
// CaptureEnd is triggered at end of execution.
|
||||
|
|
@ -80,8 +85,9 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration,
|
|||
Time time.Duration `json:"time"`
|
||||
Err string `json:"error,omitempty"`
|
||||
}
|
||||
var errMsg string
|
||||
if err != nil {
|
||||
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
|
||||
errMsg = err.Error()
|
||||
}
|
||||
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
|
||||
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, errMsg})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,17 +20,16 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type dummyContractRef struct {
|
||||
calledForEach bool
|
||||
}
|
||||
|
||||
func (dummyContractRef) ReturnGas(*big.Int) {}
|
||||
func (dummyContractRef) Address() common.Address { return common.Address{} }
|
||||
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
|
||||
func (dummyContractRef) SetCode(common.Hash, []byte) {}
|
||||
|
|
@ -57,8 +56,8 @@ func TestStoreCapture(t *testing.T) {
|
|||
stack = newstack()
|
||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||
)
|
||||
stack.push(big.NewInt(1))
|
||||
stack.push(big.NewInt(0))
|
||||
stack.push(uint256.NewInt(1))
|
||||
stack.push(new(uint256.Int))
|
||||
var index common.Hash
|
||||
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
|
||||
if len(logger.changedValues[contract.Address()]) == 0 {
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// Memory implements a simple memory model for the ethereum virtual machine.
|
||||
|
|
@ -50,16 +47,15 @@ func (m *Memory) Set(offset, size uint64, value []byte) {
|
|||
|
||||
// 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) {
|
||||
func (m *Memory) Set32(offset uint64, val *uint256.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])
|
||||
b32 := val.Bytes32()
|
||||
copy(m.store[offset:], b32[:])
|
||||
}
|
||||
|
||||
// Resize resizes the memory to size
|
||||
|
|
@ -69,7 +65,7 @@ func (m *Memory) Resize(size uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
// Get returns offset + size as a new slice
|
||||
// GetCopy returns offset + size as a new slice
|
||||
func (m *Memory) GetCopy(offset, size int64) (cpy []byte) {
|
||||
if size == 0 {
|
||||
return nil
|
||||
|
|
@ -107,18 +103,3 @@ func (m *Memory) Len() int {
|
|||
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("####################")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package vm
|
||||
|
||||
func memorySha3(stack *Stack) (uint64, bool) {
|
||||
func memoryKeccak256(stack *Stack) (uint64, bool) {
|
||||
return calcMemSize64(stack.Back(0), stack.Back(1))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,75 +32,73 @@ func (op OpCode) IsPush() bool {
|
|||
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
|
||||
STOP OpCode = 0x0
|
||||
ADD OpCode = 0x1
|
||||
MUL OpCode = 0x2
|
||||
SUB OpCode = 0x3
|
||||
DIV OpCode = 0x4
|
||||
SDIV OpCode = 0x5
|
||||
MOD OpCode = 0x6
|
||||
SMOD OpCode = 0x7
|
||||
ADDMOD OpCode = 0x8
|
||||
MULMOD OpCode = 0x9
|
||||
EXP OpCode = 0xa
|
||||
SIGNEXTEND OpCode = 0xb
|
||||
)
|
||||
|
||||
// 0x10 range - comparison ops.
|
||||
const (
|
||||
LT OpCode = iota + 0x10
|
||||
GT
|
||||
SLT
|
||||
SGT
|
||||
EQ
|
||||
ISZERO
|
||||
AND
|
||||
OR
|
||||
XOR
|
||||
NOT
|
||||
BYTE
|
||||
SHL
|
||||
SHR
|
||||
SAR
|
||||
LT OpCode = 0x10
|
||||
GT OpCode = 0x11
|
||||
SLT OpCode = 0x12
|
||||
SGT OpCode = 0x13
|
||||
EQ OpCode = 0x14
|
||||
ISZERO OpCode = 0x15
|
||||
AND OpCode = 0x16
|
||||
OR OpCode = 0x17
|
||||
XOR OpCode = 0x18
|
||||
NOT OpCode = 0x19
|
||||
BYTE OpCode = 0x1a
|
||||
SHL OpCode = 0x1b
|
||||
SHR OpCode = 0x1c
|
||||
SAR OpCode = 0x1d
|
||||
)
|
||||
|
||||
SHA3 OpCode = 0x20
|
||||
// 0x20 range - crypto.
|
||||
const (
|
||||
KECCAK256 OpCode = 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
|
||||
ADDRESS OpCode = 0x30
|
||||
BALANCE OpCode = 0x31
|
||||
ORIGIN OpCode = 0x32
|
||||
CALLER OpCode = 0x33
|
||||
CALLVALUE OpCode = 0x34
|
||||
CALLDATALOAD OpCode = 0x35
|
||||
CALLDATASIZE OpCode = 0x36
|
||||
CALLDATACOPY OpCode = 0x37
|
||||
CODESIZE OpCode = 0x38
|
||||
CODECOPY OpCode = 0x39
|
||||
GASPRICE OpCode = 0x3a
|
||||
EXTCODESIZE OpCode = 0x3b
|
||||
EXTCODECOPY OpCode = 0x3c
|
||||
RETURNDATASIZE OpCode = 0x3d
|
||||
RETURNDATACOPY OpCode = 0x3e
|
||||
EXTCODEHASH OpCode = 0x3f
|
||||
)
|
||||
|
||||
// 0x40 range - block operations.
|
||||
const (
|
||||
BLOCKHASH OpCode = 0x40 + iota
|
||||
COINBASE
|
||||
TIMESTAMP
|
||||
NUMBER
|
||||
DIFFICULTY
|
||||
GASLIMIT
|
||||
BLOCKHASH OpCode = 0x40
|
||||
COINBASE OpCode = 0x41
|
||||
TIMESTAMP OpCode = 0x42
|
||||
NUMBER OpCode = 0x43
|
||||
DIFFICULTY OpCode = 0x44
|
||||
GASLIMIT OpCode = 0x45
|
||||
CHAINID OpCode = 0x46
|
||||
SELFBALANCE OpCode = 0x47
|
||||
)
|
||||
|
|
@ -121,7 +119,7 @@ const (
|
|||
JUMPDEST
|
||||
)
|
||||
|
||||
// 0x60 range.
|
||||
// 0x60 range - pushes.
|
||||
const (
|
||||
PUSH1 OpCode = 0x60 + iota
|
||||
PUSH2
|
||||
|
|
@ -155,7 +153,11 @@ const (
|
|||
PUSH30
|
||||
PUSH31
|
||||
PUSH32
|
||||
DUP1
|
||||
)
|
||||
|
||||
// 0x80 range - dups.
|
||||
const (
|
||||
DUP1 = 0x80 + iota
|
||||
DUP2
|
||||
DUP3
|
||||
DUP4
|
||||
|
|
@ -171,7 +173,11 @@ const (
|
|||
DUP14
|
||||
DUP15
|
||||
DUP16
|
||||
SWAP1
|
||||
)
|
||||
|
||||
// 0x90 range - swaps.
|
||||
const (
|
||||
SWAP1 = 0x90 + iota
|
||||
SWAP2
|
||||
SWAP3
|
||||
SWAP4
|
||||
|
|
@ -198,28 +204,22 @@ const (
|
|||
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
|
||||
CREATE OpCode = 0xf0
|
||||
CALL OpCode = 0xf1
|
||||
CALLCODE OpCode = 0xf2
|
||||
RETURN OpCode = 0xf3
|
||||
DELEGATECALL OpCode = 0xf4
|
||||
CREATE2 OpCode = 0xf5
|
||||
|
||||
STATICCALL OpCode = 0xfa
|
||||
REVERT OpCode = 0xfd
|
||||
INVALID OpCode = 0xfe
|
||||
SELFDESTRUCT OpCode = 0xff
|
||||
)
|
||||
|
||||
// Since the opcodes aren't all in order we can't use a regular slice.
|
||||
var opCodeToString = map[OpCode]string{
|
||||
var opCodeToString = [256]string{
|
||||
// 0x0 range - arithmetic ops.
|
||||
STOP: "STOP",
|
||||
ADD: "ADD",
|
||||
|
|
@ -251,7 +251,7 @@ var opCodeToString = map[OpCode]string{
|
|||
MULMOD: "MULMOD",
|
||||
|
||||
// 0x20 range - crypto.
|
||||
SHA3: "SHA3",
|
||||
KECCAK256: "KECCAK256",
|
||||
|
||||
// 0x30 range - closure state.
|
||||
ADDRESS: "ADDRESS",
|
||||
|
|
@ -379,20 +379,16 @@ var opCodeToString = map[OpCode]string{
|
|||
CREATE2: "CREATE2",
|
||||
STATICCALL: "STATICCALL",
|
||||
REVERT: "REVERT",
|
||||
INVALID: "INVALID",
|
||||
SELFDESTRUCT: "SELFDESTRUCT",
|
||||
|
||||
PUSH: "PUSH",
|
||||
DUP: "DUP",
|
||||
SWAP: "SWAP",
|
||||
}
|
||||
|
||||
func (op OpCode) String() string {
|
||||
str := opCodeToString[op]
|
||||
if len(str) == 0 {
|
||||
return fmt.Sprintf("opcode 0x%x not defined", int(op))
|
||||
if s := opCodeToString[op]; s != "" {
|
||||
return s
|
||||
}
|
||||
|
||||
return str
|
||||
return fmt.Sprintf("opcode %#x not defined", int(op))
|
||||
}
|
||||
|
||||
var stringToOp = map[string]OpCode{
|
||||
|
|
@ -422,7 +418,7 @@ var stringToOp = map[string]OpCode{
|
|||
"SAR": SAR,
|
||||
"ADDMOD": ADDMOD,
|
||||
"MULMOD": MULMOD,
|
||||
"SHA3": SHA3,
|
||||
"KECCAK256": KECCAK256,
|
||||
"ADDRESS": ADDRESS,
|
||||
"BALANCE": BALANCE,
|
||||
"ORIGIN": ORIGIN,
|
||||
|
|
@ -536,6 +532,7 @@ var stringToOp = map[string]OpCode{
|
|||
"RETURN": RETURN,
|
||||
"CALLCODE": CALLCODE,
|
||||
"REVERT": REVERT,
|
||||
"INVALID": INVALID,
|
||||
"SELFDESTRUCT": SELFDESTRUCT,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,37 +17,31 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// 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
|
||||
data []uint256.Int
|
||||
}
|
||||
|
||||
func newstack() *Stack {
|
||||
return &Stack{data: make([]*big.Int, 0, 1024)}
|
||||
return &Stack{data: make([]uint256.Int, 0, 16)}
|
||||
}
|
||||
|
||||
// Data returns the underlying big.Int array.
|
||||
func (st *Stack) Data() []*big.Int {
|
||||
// Data returns the underlying uint256.Int array.
|
||||
func (st *Stack) Data() []uint256.Int {
|
||||
return st.data
|
||||
}
|
||||
|
||||
func (st *Stack) push(d *big.Int) {
|
||||
func (st *Stack) push(d *uint256.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...)
|
||||
st.data = append(st.data, *d)
|
||||
}
|
||||
|
||||
func (st *Stack) pop() (ret *big.Int) {
|
||||
func (st *Stack) pop() (ret uint256.Int) {
|
||||
ret = st.data[len(st.data)-1]
|
||||
st.data = st.data[:len(st.data)-1]
|
||||
return
|
||||
|
|
@ -61,28 +55,15 @@ 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) dup(n int) {
|
||||
st.push(&st.data[st.len()-n])
|
||||
}
|
||||
|
||||
func (st *Stack) peek() *big.Int {
|
||||
return st.data[st.len()-1]
|
||||
func (st *Stack) peek() *uint256.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]
|
||||
}
|
||||
|
||||
// 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("#############")
|
||||
func (st *Stack) Back(n int) *uint256.Int {
|
||||
return &st.data[st.len()-n-1]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
"result": {
|
||||
"calls": [
|
||||
{
|
||||
"error": "invalid opcode: opcode 0xfe not defined",
|
||||
"error": "invalid opcode: INVALID",
|
||||
"from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
|
||||
"gas": "0x75fe3",
|
||||
"gasUsed": "0x75fe3",
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ func (sw *stackWrapper) peek(idx int) *big.Int {
|
|||
log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
|
||||
return new(big.Int)
|
||||
}
|
||||
return sw.stack.Data()[len(sw.stack.Data())-idx-1]
|
||||
return sw.stack.Back(idx).ToBig()
|
||||
}
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable stack and pushes it
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ func (account) SetBalance(*big.Int) {}
|
|||
func (account) SetNonce(uint64) {}
|
||||
func (account) Balance() *big.Int { return nil }
|
||||
func (account) Address() common.Address { return common.Address{} }
|
||||
func (account) ReturnGas(*big.Int) {}
|
||||
func (account) SetCode(common.Hash, []byte) {}
|
||||
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
||||
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -20,6 +20,7 @@ require (
|
|||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/golang-lru v0.5.3
|
||||
github.com/holiman/uint256 v1.2.4
|
||||
github.com/huin/goupnp v1.3.0
|
||||
github.com/influxdata/influxdb v1.7.9
|
||||
github.com/jackpal/go-nat-pmp v1.0.2
|
||||
|
|
@ -61,7 +62,6 @@ require (
|
|||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -140,6 +140,8 @@ github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8
|
|||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
||||
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ const (
|
|||
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||
|
||||
Sha3Gas uint64 = 30 // Once per SHA3 operation.
|
||||
Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data.
|
||||
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
||||
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
||||
SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero.
|
||||
SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change.
|
||||
SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
|
||||
|
|
@ -98,14 +98,10 @@ const (
|
|||
NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value
|
||||
NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value
|
||||
|
||||
SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
|
||||
SstoreNoopGasEIP2200 uint64 = 800 // Once per SSTORE operation if the value doesn't change.
|
||||
SstoreDirtyGasEIP2200 uint64 = 800 // Once per SSTORE operation if a dirty value is changed.
|
||||
SstoreInitGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
|
||||
SstoreInitRefundEIP2200 uint64 = 19200 // Once per SSTORE operation for resetting to the original zero value
|
||||
SstoreCleanGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
|
||||
SstoreCleanRefundEIP2200 uint64 = 4200 // Once per SSTORE operation for resetting to the original non-zero value
|
||||
SstoreClearRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
|
||||
SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
|
||||
SstoreSetGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
|
||||
SstoreResetGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
|
||||
SstoreClearsScheduleRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
|
||||
|
||||
Create2Gas uint64 = 32000 // Once per CREATE2 operation
|
||||
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/XinFinOrg/XDPoSChain/core"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
|
|
@ -143,7 +143,6 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
|
|||
Difficulty: t.json.Env.Difficulty,
|
||||
GasPrice: t.json.Exec.GasPrice,
|
||||
}
|
||||
vmconfig.NoRecursion = true
|
||||
return vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue