mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 09:50:45 +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()
|
log.Memory = memory.Data()
|
||||||
}
|
}
|
||||||
if !l.cfg.DisableStack {
|
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)
|
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 {
|
func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
|
||||||
stateObject := newObject(db, self.address, self.data, onDirty)
|
stateObject := newObject(db, self.address, self.data, onDirty)
|
||||||
if self.trie != nil {
|
if self.trie != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
const (
|
const (
|
||||||
set2BitsMask = uint16(0b1100_0000_0000_0000)
|
set2BitsMask = uint16(0b11)
|
||||||
set3BitsMask = uint16(0b1110_0000_0000_0000)
|
set3BitsMask = uint16(0b111)
|
||||||
set4BitsMask = uint16(0b1111_0000_0000_0000)
|
set4BitsMask = uint16(0b1111)
|
||||||
set5BitsMask = uint16(0b1111_1000_0000_0000)
|
set5BitsMask = uint16(0b1_1111)
|
||||||
set6BitsMask = uint16(0b1111_1100_0000_0000)
|
set6BitsMask = uint16(0b11_1111)
|
||||||
set7BitsMask = uint16(0b1111_1110_0000_0000)
|
set7BitsMask = uint16(0b111_1111)
|
||||||
)
|
)
|
||||||
|
|
||||||
// bitvec is a bit vector which maps bytes in a program.
|
// bitvec is a bit vector which maps bytes in a program.
|
||||||
|
|
@ -30,32 +30,26 @@ const (
|
||||||
// it's data (i.e. argument of PUSHxx).
|
// it's data (i.e. argument of PUSHxx).
|
||||||
type bitvec []byte
|
type bitvec []byte
|
||||||
|
|
||||||
var lookup = [8]byte{
|
|
||||||
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bits bitvec) set1(pos uint64) {
|
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) {
|
func (bits bitvec) setN(flag uint16, pos uint64) {
|
||||||
a := flag >> (pos % 8)
|
a := flag << (pos % 8)
|
||||||
bits[pos/8] |= byte(a >> 8)
|
bits[pos/8] |= byte(a)
|
||||||
if b := byte(a); b != 0 {
|
if b := byte(a >> 8); 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
|
|
||||||
bits[pos/8+1] = b
|
bits[pos/8+1] = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bits bitvec) set8(pos uint64) {
|
func (bits bitvec) set8(pos uint64) {
|
||||||
a := byte(0xFF >> (pos % 8))
|
a := byte(0xFF << (pos % 8))
|
||||||
bits[pos/8] |= a
|
bits[pos/8] |= a
|
||||||
bits[pos/8+1] = ^a
|
bits[pos/8+1] = ^a
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bits bitvec) set16(pos uint64) {
|
func (bits bitvec) set16(pos uint64) {
|
||||||
a := byte(0xFF >> (pos % 8))
|
a := byte(0xFF << (pos % 8))
|
||||||
bits[pos/8] |= a
|
bits[pos/8] |= a
|
||||||
bits[pos/8+1] = 0xFF
|
bits[pos/8+1] = 0xFF
|
||||||
bits[pos/8+2] = ^a
|
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.
|
// codeSegment checks if the position is in a code segment.
|
||||||
func (bits *bitvec) codeSegment(pos uint64) bool {
|
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.
|
// codeBitmap collects data locations in code.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/bits"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
|
|
@ -28,24 +29,27 @@ func TestJumpDestAnalysis(t *testing.T) {
|
||||||
exp byte
|
exp byte
|
||||||
which int
|
which int
|
||||||
}{
|
}{
|
||||||
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0x40, 0},
|
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
|
||||||
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0x50, 0},
|
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0},
|
||||||
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, 0x7F, 0},
|
{[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0},
|
||||||
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 1},
|
{[]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{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0x03, 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), 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
|
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
|
||||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x74, 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}, 0x00, 1},
|
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
|
||||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x3F, 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}, 0xC0, 1},
|
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
|
||||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x7F, 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}, 0xFF, 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}, 0x80, 2},
|
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
|
||||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0x7f, 0},
|
{[]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}, 0xA0, 1},
|
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0},
|
||||||
{[]byte{byte(PUSH32)}, 0x7F, 0},
|
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1},
|
||||||
{[]byte{byte(PUSH32)}, 0xFF, 1},
|
{[]byte{byte(PUSH32)}, 0b1111_1110, 0},
|
||||||
{[]byte{byte(PUSH32)}, 0xFF, 2},
|
{[]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 {
|
for i, test := range tests {
|
||||||
ret := codeBitmap(test.code)
|
ret := codeBitmap(test.code)
|
||||||
|
|
@ -55,9 +59,12 @@ func TestJumpDestAnalysis(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const analysisCodeSize = 1200 * 1024
|
||||||
|
|
||||||
func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
||||||
// 1.4 ms
|
// 1.4 ms
|
||||||
code := make([]byte, 1200000)
|
code := make([]byte, analysisCodeSize)
|
||||||
|
bench.SetBytes(analysisCodeSize)
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
codeBitmap(code)
|
codeBitmap(code)
|
||||||
|
|
@ -66,7 +73,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
||||||
}
|
}
|
||||||
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
||||||
// 4 ms
|
// 4 ms
|
||||||
code := make([]byte, 1200000)
|
code := make([]byte, analysisCodeSize)
|
||||||
|
bench.SetBytes(analysisCodeSize)
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
crypto.Keccak256Hash(code)
|
crypto.Keccak256Hash(code)
|
||||||
|
|
@ -77,13 +85,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
||||||
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
|
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
|
||||||
var op OpCode
|
var op OpCode
|
||||||
bencher := func(b *testing.B) {
|
bencher := func(b *testing.B) {
|
||||||
code := make([]byte, 32*b.N)
|
code := make([]byte, analysisCodeSize)
|
||||||
|
b.SetBytes(analysisCodeSize)
|
||||||
for i := range code {
|
for i := range code {
|
||||||
code[i] = byte(op)
|
code[i] = byte(op)
|
||||||
}
|
}
|
||||||
bits := make(bitvec, len(code)/8+1+4)
|
bits := make(bitvec, len(code)/8+1+4)
|
||||||
b.ResetTimer()
|
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++ {
|
for op = PUSH1; op <= PUSH32; op++ {
|
||||||
bench.Run(op.String(), bencher)
|
bench.Run(op.String(), bencher)
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,14 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// calcMemSize64 calculates the required memory size, and returns
|
// calcMemSize64 calculates the required memory size, and returns
|
||||||
// the size and whether the result overflowed uint64
|
// 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() {
|
if !l.IsUint64() {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
|
|
@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
|
||||||
// calcMemSize64WithUint calculates the required memory size, and returns
|
// calcMemSize64WithUint calculates the required memory size, and returns
|
||||||
// the size and whether the result overflowed uint64
|
// the size and whether the result overflowed uint64
|
||||||
// Identical to calcMemSize64, but length is a 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 length is zero, memsize is always zero, regardless of offset
|
||||||
if length64 == 0 {
|
if length64 == 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
// Check that offset doesn't overflow
|
// Check that offset doesn't overflow
|
||||||
if !off.IsUint64() {
|
offset64, overflow := off.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
offset64 := off.Uint64()
|
|
||||||
val := offset64 + length64
|
val := offset64 + length64
|
||||||
// if value < either of it's parts, then it overflowed
|
// if value < either of it's parts, then it overflowed
|
||||||
return val, val < offset64
|
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))
|
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.
|
// toWordSize returns the ceiled word size required for memory expansion.
|
||||||
func toWordSize(size uint64) uint64 {
|
func toWordSize(size uint64) uint64 {
|
||||||
if size > math.MaxUint64-31 {
|
if size > math.MaxUint64-31 {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContractRef is a reference to the contract's backing object
|
// 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
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contract) validJumpdest(dest *big.Int) bool {
|
func (c *Contract) validJumpdest(dest *uint256.Int) bool {
|
||||||
udest := dest.Uint64()
|
udest, overflow := dest.Uint64WithOverflow()
|
||||||
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
|
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
|
||||||
// Don't bother checking for JUMPDEST in that case.
|
// 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
|
return false
|
||||||
}
|
}
|
||||||
// Only JUMPDESTs allowed for destinations
|
// 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
|
// GetOp returns the n'th element in the contract's byte array
|
||||||
func (c *Contract) GetOp(n uint64) OpCode {
|
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)) {
|
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.
|
// 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
|
// Parse the input into the Blake2b call parameters
|
||||||
var (
|
var (
|
||||||
rounds = binary.BigEndian.Uint32(input[0:4])
|
rounds = binary.BigEndian.Uint32(input[0:4])
|
||||||
final = (input[212] == blake2FFinalBlockBytes)
|
final = input[212] == blake2FFinalBlockBytes
|
||||||
|
|
||||||
h [8]uint64
|
h [8]uint64
|
||||||
m [16]uint64
|
m [16]uint64
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnableEIP enables the given EIP on the config.
|
// EnableEIP enables the given EIP on the config.
|
||||||
|
|
@ -51,17 +52,16 @@ func enable1884(jt *JumpTable) {
|
||||||
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
|
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
|
||||||
|
|
||||||
// New opcode
|
// New opcode
|
||||||
jt[SELFBALANCE] = operation{
|
jt[SELFBALANCE] = &operation{
|
||||||
execute: opSelfBalance,
|
execute: opSelfBalance,
|
||||||
constantGas: GasFastStep,
|
constantGas: GasFastStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
valid: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
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)
|
callContext.stack.push(balance)
|
||||||
return nil, nil
|
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
|
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
|
||||||
func enable1344(jt *JumpTable) {
|
func enable1344(jt *JumpTable) {
|
||||||
// New opcode
|
// New opcode
|
||||||
jt[CHAINID] = operation{
|
jt[CHAINID] = &operation{
|
||||||
execute: opChainID,
|
execute: opChainID,
|
||||||
constantGas: GasQuickStep,
|
constantGas: GasQuickStep,
|
||||||
minStack: minStack(0, 1),
|
minStack: minStack(0, 1),
|
||||||
maxStack: maxStack(0, 1),
|
maxStack: maxStack(0, 1),
|
||||||
valid: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// opChainID implements CHAINID opcode
|
// opChainID implements CHAINID opcode
|
||||||
func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
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)
|
callContext.stack.push(chainId)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ var (
|
||||||
ErrWriteProtection = errors.New("write protection")
|
ErrWriteProtection = errors.New("write protection")
|
||||||
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
||||||
ErrGasUintOverflow = errors.New("gas uint64 overflow")
|
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
|
// 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
|
// the necessary steps to create accounts and reverses the state in case of an
|
||||||
// execution error or failed value transfer.
|
// 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) {
|
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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
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'
|
// CallCode differs from Call in the sense that it executes the given address'
|
||||||
// code with the caller as context.
|
// 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) {
|
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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
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'
|
// 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.
|
// 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) {
|
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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
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
|
// Opcodes that attempt to perform such modifications will result in exceptions
|
||||||
// instead of performing the modifications.
|
// instead of performing the modifications.
|
||||||
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
|
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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
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,
|
// 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
|
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||||
// future scenarios
|
// 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
|
// 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 := NewContract(caller, AccountRef(address), value, gas)
|
||||||
contract.SetCodeOptionalHash(&address, codeAndHash)
|
contract.SetCodeOptionalHash(&address, codeAndHash)
|
||||||
|
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
|
||||||
return nil, address, gas, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
|
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)
|
ret, err := run(evm, contract, nil, false)
|
||||||
|
|
||||||
// check whether the max code size has been exceeded
|
// Check whether the max code size has been exceeded, assign err if the case.
|
||||||
maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
|
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
||||||
|
err = ErrMaxCodeSizeExceeded
|
||||||
|
}
|
||||||
|
|
||||||
// if the contract creation ran successfully and no errors were returned
|
// if the contract creation ran successfully and no errors were returned
|
||||||
// calculate the gas required to store the code. If the code could not
|
// 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
|
// be stored due to not enough gas set an error and let it be handled
|
||||||
// by the error checking condition below.
|
// by the error checking condition below.
|
||||||
if err == nil && !maxCodeSizeExceeded {
|
if err == nil {
|
||||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||||
if contract.UseGas(createDataGas) {
|
if contract.UseGas(createDataGas) {
|
||||||
evm.StateDB.SetCode(address, ret)
|
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
|
// 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
|
// 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.
|
// 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)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
contract.UseGas(contract.Gas)
|
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 {
|
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||||
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
||||||
}
|
}
|
||||||
return ret, address, contract.Gas, err
|
return ret, address, contract.Gas, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// 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.
|
// 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.
|
// 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) {
|
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}
|
codeAndHash := &codeAndHash{code: code}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas costs
|
// Gas costs
|
||||||
|
|
@ -34,7 +34,7 @@ const (
|
||||||
//
|
//
|
||||||
// The cost of gas was changed during the homestead price change HF.
|
// 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.
|
// 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 {
|
if isEip150 {
|
||||||
availableGas = availableGas - base
|
availableGas = availableGas - base
|
||||||
gas := availableGas - availableGas/64
|
gas := availableGas - availableGas/64
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
||||||
// as argument:
|
// as argument:
|
||||||
// CALLDATACOPY (stack position 2)
|
// CALLDATACOPY (stack position 2)
|
||||||
// CODECOPY (stack position 2)
|
// CODECOPY (stack position 2)
|
||||||
// EXTCODECOPY (stack poition 3)
|
// EXTCODECOPY (stack position 3)
|
||||||
// RETURNDATACOPY (stack position 2)
|
// RETURNDATACOPY (stack position 2)
|
||||||
func memoryCopierGas(stackpos int) gasFunc {
|
func memoryCopierGas(stackpos int) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
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
|
return 0, err
|
||||||
}
|
}
|
||||||
// And gas for copying data, charged per word at param.CopyGas
|
// 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 {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ var (
|
||||||
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
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
|
// 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)
|
// 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. 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.1. If original value is 0, add 19800 gas to refund counter.
|
||||||
// 2.2.2.2. Otherwise, add 4800 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)
|
if current == value { // noop (1)
|
||||||
return params.NetSstoreNoopGas, nil
|
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 == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return params.NetSstoreInitGas, nil
|
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.
|
// 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. 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. 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.1. If original value is 0, SSTORE_SET_GAS (20K) 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.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), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses:
|
// 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. 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.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_CLEAR_REFUND gas to 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. 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.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
|
||||||
// 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND 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) {
|
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 we fail the minimum gas availability invariant, fail (0)
|
||||||
if contract.Gas <= params.SstoreSentryGasEIP2200 {
|
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
|
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
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)
|
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 == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
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)
|
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 original != (common.Hash{}) {
|
||||||
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
|
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)
|
} 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 == value {
|
||||||
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
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)
|
} 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 {
|
func makeGasLog(n uint64) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
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 {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
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)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
wordGas, overflow := bigUint64(stack.Back(1))
|
wordGas, overflow := stack.Back(1).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
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
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
wordGas, overflow := bigUint64(stack.Back(2))
|
wordGas, overflow := stack.Back(2).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
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
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
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) {
|
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
gas uint64
|
gas uint64
|
||||||
transfersValue = stack.Back(2).Sign() != 0
|
transfersValue = !stack.Back(2).IsZero()
|
||||||
address = common.BigToAddress(stack.Back(1))
|
address = common.Address(stack.Back(1).Bytes20())
|
||||||
)
|
)
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
if transfersValue && evm.StateDB.Empty(address) {
|
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:
|
// EIP150 homestead gas reprice fork:
|
||||||
if evm.chainRules.IsEIP150 {
|
if evm.chainRules.IsEIP150 {
|
||||||
gas = params.SelfdestructGasEIP150
|
gas = params.SelfdestructGasEIP150
|
||||||
var address = common.BigToAddress(stack.Back(0))
|
var address = common.Address(stack.Back(0).Bytes20())
|
||||||
|
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
// if empty and transfers value
|
// if empty and transfers value
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -21,14 +21,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TwoOperandTestcase struct {
|
type TwoOperandTestcase struct {
|
||||||
|
|
@ -42,6 +41,7 @@ type twoOperandParams struct {
|
||||||
y string
|
y string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||||
var commonParams []*twoOperandParams
|
var commonParams []*twoOperandParams
|
||||||
var twoOpMethods map[string]executionFunc
|
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) {
|
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -124,42 +99,23 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
evmInterpreter = env.interpreter.(*EVMInterpreter)
|
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 {
|
for i, test := range tests {
|
||||||
x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
|
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X))
|
||||||
y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y))
|
||||||
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
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()
|
actual := stack.pop()
|
||||||
|
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
|
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) {
|
func TestByteOp(t *testing.T) {
|
||||||
|
|
@ -235,6 +191,68 @@ func TestSAR(t *testing.T) {
|
||||||
testTwoOperandOp(t, tests, opSAR, "sar")
|
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
|
// utility function to fill the json-file with testcases
|
||||||
// Enable this test to generate the 'testcases_xx.json' files
|
// Enable this test to generate the 'testcases_xx.json' files
|
||||||
func TestWriteExpectedValues(t *testing.T) {
|
func TestWriteExpectedValues(t *testing.T) {
|
||||||
|
|
@ -276,7 +294,6 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||||
)
|
)
|
||||||
|
|
||||||
env.interpreter = evmInterpreter
|
env.interpreter = evmInterpreter
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
|
||||||
// convert args
|
// convert args
|
||||||
byteArgs := make([][]byte, len(args))
|
byteArgs := make([][]byte, len(args))
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
|
|
@ -286,13 +303,13 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
for _, arg := range byteArgs {
|
for _, arg := range byteArgs {
|
||||||
a := new(big.Int).SetBytes(arg)
|
a := new(uint256.Int)
|
||||||
|
a.SetBytes(arg)
|
||||||
stack.push(a)
|
stack.push(a)
|
||||||
}
|
}
|
||||||
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
||||||
stack.pop()
|
stack.pop()
|
||||||
}
|
}
|
||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpAdd64(b *testing.B) {
|
func BenchmarkOpAdd64(b *testing.B) {
|
||||||
|
|
@ -338,8 +355,8 @@ func BenchmarkOpSub256(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpMul(b *testing.B) {
|
func BenchmarkOpMul(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opMul, x, y)
|
opBenchmark(b, opMul, x, y)
|
||||||
}
|
}
|
||||||
|
|
@ -370,64 +387,64 @@ func BenchmarkOpSdiv(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpMod(b *testing.B) {
|
func BenchmarkOpMod(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opMod, x, y)
|
opBenchmark(b, opMod, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpSmod(b *testing.B) {
|
func BenchmarkOpSmod(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opSmod, x, y)
|
opBenchmark(b, opSmod, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpExp(b *testing.B) {
|
func BenchmarkOpExp(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opExp, x, y)
|
opBenchmark(b, opExp, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpSignExtend(b *testing.B) {
|
func BenchmarkOpSignExtend(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opSignExtend, x, y)
|
opBenchmark(b, opSignExtend, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpLt(b *testing.B) {
|
func BenchmarkOpLt(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opLt, x, y)
|
opBenchmark(b, opLt, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpGt(b *testing.B) {
|
func BenchmarkOpGt(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opGt, x, y)
|
opBenchmark(b, opGt, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpSlt(b *testing.B) {
|
func BenchmarkOpSlt(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opSlt, x, y)
|
opBenchmark(b, opSlt, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpSgt(b *testing.B) {
|
func BenchmarkOpSgt(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opSgt, x, y)
|
opBenchmark(b, opSgt, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpEq(b *testing.B) {
|
func BenchmarkOpEq(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opEq, x, y)
|
opBenchmark(b, opEq, x, y)
|
||||||
}
|
}
|
||||||
|
|
@ -437,45 +454,45 @@ func BenchmarkOpEq2(b *testing.B) {
|
||||||
opBenchmark(b, opEq, x, y)
|
opBenchmark(b, opEq, x, y)
|
||||||
}
|
}
|
||||||
func BenchmarkOpAnd(b *testing.B) {
|
func BenchmarkOpAnd(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opAnd, x, y)
|
opBenchmark(b, opAnd, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpOr(b *testing.B) {
|
func BenchmarkOpOr(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opOr, x, y)
|
opBenchmark(b, opOr, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpXor(b *testing.B) {
|
func BenchmarkOpXor(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opXor, x, y)
|
opBenchmark(b, opXor, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpByte(b *testing.B) {
|
func BenchmarkOpByte(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opByte, x, y)
|
opBenchmark(b, opByte, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpAddmod(b *testing.B) {
|
func BenchmarkOpAddmod(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
z := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opAddmod, x, y, z)
|
opBenchmark(b, opAddmod, x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpMulmod(b *testing.B) {
|
func BenchmarkOpMulmod(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := alphabetSoup
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := alphabetSoup
|
||||||
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
z := alphabetSoup
|
||||||
|
|
||||||
opBenchmark(b, opMulmod, x, y, z)
|
opBenchmark(b, opMulmod, x, y, z)
|
||||||
}
|
}
|
||||||
|
|
@ -512,21 +529,21 @@ func TestOpMstore(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
env.interpreter = evmInterpreter
|
env.interpreter = evmInterpreter
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
|
||||||
mem.Resize(64)
|
mem.Resize(64)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
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})
|
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||||
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
||||||
t.Fatalf("Mstore fail, got %v, expected %v", 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})
|
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||||
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||||
t.Fatalf("Mstore failed to overwrite previous value")
|
t.Fatalf("Mstore failed to overwrite previous value")
|
||||||
}
|
}
|
||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpMstore(bench *testing.B) {
|
func BenchmarkOpMstore(bench *testing.B) {
|
||||||
|
|
@ -538,21 +555,20 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
)
|
)
|
||||||
|
|
||||||
env.interpreter = evmInterpreter
|
env.interpreter = evmInterpreter
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
|
||||||
mem.Resize(64)
|
mem.Resize(64)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
memStart := big.NewInt(0)
|
memStart := new(uint256.Int)
|
||||||
value := big.NewInt(0x1337)
|
value := new(uint256.Int).SetUint64(0x1337)
|
||||||
|
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.pushN(value, memStart)
|
stack.push(value)
|
||||||
|
stack.push(memStart)
|
||||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||||
}
|
}
|
||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkOpSHA3(bench *testing.B) {
|
func BenchmarkOpKeccak256(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
@ -560,17 +576,16 @@ func BenchmarkOpSHA3(bench *testing.B) {
|
||||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||||
)
|
)
|
||||||
env.interpreter = evmInterpreter
|
env.interpreter = evmInterpreter
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
|
||||||
mem.Resize(32)
|
mem.Resize(32)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
start := big.NewInt(0)
|
start := new(uint256.Int)
|
||||||
|
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.pushN(big.NewInt(32), start)
|
stack.push(uint256.NewInt(32))
|
||||||
opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
stack.push(start)
|
||||||
|
opKeccak256(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
||||||
}
|
}
|
||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreate2Addreses(t *testing.T) {
|
func TestCreate2Addreses(t *testing.T) {
|
||||||
|
|
@ -644,6 +659,5 @@ func TestCreate2Addreses(t *testing.T) {
|
||||||
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
|
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
|
||||||
t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String())
|
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 (
|
import (
|
||||||
"hash"
|
"hash"
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||||
|
|
@ -29,10 +28,9 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool // Enables debugging
|
Debug bool // Enables debugging
|
||||||
Tracer Tracer // Opcode logger
|
Tracer Tracer // Opcode logger
|
||||||
NoRecursion bool // Disables call, callcode, delegate call and create
|
|
||||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
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
|
EWASMInterpreter string // External EWASM interpreter options
|
||||||
EVMInterpreter string // External EVM interpreter options
|
EVMInterpreter string // External EVM interpreter options
|
||||||
|
|
@ -83,8 +81,6 @@ type EVMInterpreter struct {
|
||||||
evm *EVM
|
evm *EVM
|
||||||
cfg Config
|
cfg Config
|
||||||
|
|
||||||
intPool *intPool
|
|
||||||
|
|
||||||
hasher keccakState // Keccak256 hasher instance shared across opcodes
|
hasher keccakState // Keccak256 hasher instance shared across opcodes
|
||||||
hasherBuf common.Hash // Keccak256 hasher result array shared aross 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.
|
// NewEVMInterpreter returns a new instance of the Interpreter.
|
||||||
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
||||||
// We use the STOP instruction whether to see
|
// If jump table was not initialised we set the default one.
|
||||||
// the jump table was initialised. If it was not
|
if cfg.JumpTable == nil {
|
||||||
// we'll set the default jump table.
|
|
||||||
if !cfg.JumpTable[STOP].valid {
|
|
||||||
var jt JumpTable
|
|
||||||
switch {
|
switch {
|
||||||
case evm.chainRules.IsIstanbul:
|
case evm.chainRules.IsIstanbul:
|
||||||
jt = istanbulInstructionSet
|
cfg.JumpTable = &istanbulInstructionSet
|
||||||
case evm.chainRules.IsConstantinople:
|
case evm.chainRules.IsConstantinople:
|
||||||
jt = constantinopleInstructionSet
|
cfg.JumpTable = &constantinopleInstructionSet
|
||||||
case evm.chainRules.IsByzantium:
|
case evm.chainRules.IsByzantium:
|
||||||
jt = byzantiumInstructionSet
|
cfg.JumpTable = &byzantiumInstructionSet
|
||||||
case evm.chainRules.IsEIP158:
|
case evm.chainRules.IsEIP158:
|
||||||
jt = spuriousDragonInstructionSet
|
cfg.JumpTable = &spuriousDragonInstructionSet
|
||||||
case evm.chainRules.IsEIP150:
|
case evm.chainRules.IsEIP150:
|
||||||
jt = tangerineWhistleInstructionSet
|
cfg.JumpTable = &tangerineWhistleInstructionSet
|
||||||
case evm.chainRules.IsHomestead:
|
case evm.chainRules.IsHomestead:
|
||||||
jt = homesteadInstructionSet
|
cfg.JumpTable = &homesteadInstructionSet
|
||||||
default:
|
default:
|
||||||
jt = frontierInstructionSet
|
cfg.JumpTable = &frontierInstructionSet
|
||||||
}
|
}
|
||||||
for i, eip := range cfg.ExtraEips {
|
var extraEips []int
|
||||||
if err := EnableEIP(eip, &jt); err != nil {
|
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
|
// 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)
|
log.Error("EIP activation failed", "eip", eip, "error", err)
|
||||||
|
} else {
|
||||||
|
extraEips = append(extraEips, eip)
|
||||||
}
|
}
|
||||||
|
cfg.JumpTable = ©
|
||||||
}
|
}
|
||||||
cfg.JumpTable = jt
|
cfg.ExtraEips = extraEips
|
||||||
}
|
}
|
||||||
|
|
||||||
return &EVMInterpreter{
|
return &EVMInterpreter{
|
||||||
|
|
@ -138,20 +135,13 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
||||||
// considered a revert-and-consume-all-gas operation except for
|
// considered a revert-and-consume-all-gas operation except for
|
||||||
// ErrExecutionReverted which means revert-and-keep-gas-left.
|
// ErrExecutionReverted which means revert-and-keep-gas-left.
|
||||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
|
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
|
// Increment the call depth which is restricted to 1024
|
||||||
in.evm.depth++
|
in.evm.depth++
|
||||||
defer func() { in.evm.depth-- }()
|
defer func() { in.evm.depth-- }()
|
||||||
|
|
||||||
// Make sure the readOnly is only set if we aren't in readOnly yet.
|
// 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 {
|
if readOnly && !in.readOnly {
|
||||||
in.readOnly = true
|
in.readOnly = true
|
||||||
defer func() { in.readOnly = false }()
|
defer func() { in.readOnly = false }()
|
||||||
|
|
@ -188,9 +178,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
)
|
)
|
||||||
contract.Input = input
|
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 {
|
if in.cfg.Debug {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
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
|
// 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
|
// the execution of one of the operations or until the done flag is set by the
|
||||||
// parent context.
|
// parent context.
|
||||||
steps := 0
|
|
||||||
for {
|
for {
|
||||||
steps++
|
|
||||||
if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if in.cfg.Debug {
|
if in.cfg.Debug {
|
||||||
// Capture pre-execution values for tracing.
|
// Capture pre-execution values for tracing.
|
||||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
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.
|
// enough stack items available to perform the operation.
|
||||||
op = contract.GetOp(pc)
|
op = contract.GetOp(pc)
|
||||||
operation := in.cfg.JumpTable[op]
|
operation := in.cfg.JumpTable[op]
|
||||||
if !operation.valid {
|
|
||||||
return nil, &ErrInvalidOpCode{opcode: op}
|
|
||||||
}
|
|
||||||
// Validate stack
|
// Validate stack
|
||||||
if sLen := stack.len(); sLen < operation.minStack {
|
if sLen := stack.len(); sLen < operation.minStack {
|
||||||
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
||||||
} else if sLen > operation.maxStack {
|
} else if sLen > operation.maxStack {
|
||||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: 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
|
// Static portion of gas
|
||||||
cost = operation.constantGas // For tracing
|
cost = operation.constantGas // For tracing
|
||||||
if !contract.UseGas(operation.constantGas) {
|
if !contract.UseGas(operation.constantGas) {
|
||||||
|
|
@ -285,29 +253,17 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
|
|
||||||
// execute the operation
|
// execute the operation
|
||||||
res, err = operation.execute(&pc, in, callContext)
|
res, err = operation.execute(&pc, in, callContext)
|
||||||
// verifyPool is a build flag. Pool verification makes sure the integrity
|
if err != nil {
|
||||||
// of the integer pool by comparing values to a default value.
|
break
|
||||||
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++
|
|
||||||
}
|
}
|
||||||
|
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
|
// 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.
|
// it in the local storage container.
|
||||||
if op == SSTORE && stack.len() >= 2 {
|
if op == SSTORE && stack.len() >= 2 {
|
||||||
var (
|
var (
|
||||||
value = common.BigToHash(stack.data[stack.len()-2])
|
value = common.Hash(stack.data[stack.len()-2].Bytes32())
|
||||||
address = common.BigToHash(stack.data[stack.len()-1])
|
address = common.Hash(stack.data[stack.len()-1].Bytes32())
|
||||||
)
|
)
|
||||||
l.changedValues[contract.Address()][address] = value
|
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 {
|
if !l.cfg.DisableStack {
|
||||||
stck = make([]*big.Int, len(stack.Data()))
|
stck = make([]*big.Int, len(stack.Data()))
|
||||||
for i, item := range 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
|
// 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()
|
log.Memory = memory.Data()
|
||||||
}
|
}
|
||||||
if !l.cfg.DisableStack {
|
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)
|
return l.encoder.Encode(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureFault outputs state information on the logger.
|
// 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 {
|
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.
|
// 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"`
|
Time time.Duration `json:"time"`
|
||||||
Err string `json:"error,omitempty"`
|
Err string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
var errMsg string
|
||||||
if err != nil {
|
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"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dummyContractRef struct {
|
type dummyContractRef struct {
|
||||||
calledForEach bool
|
calledForEach bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dummyContractRef) ReturnGas(*big.Int) {}
|
|
||||||
func (dummyContractRef) Address() common.Address { return common.Address{} }
|
func (dummyContractRef) Address() common.Address { return common.Address{} }
|
||||||
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
|
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
|
||||||
func (dummyContractRef) SetCode(common.Hash, []byte) {}
|
func (dummyContractRef) SetCode(common.Hash, []byte) {}
|
||||||
|
|
@ -57,8 +56,8 @@ func TestStoreCapture(t *testing.T) {
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||||
)
|
)
|
||||||
stack.push(big.NewInt(1))
|
stack.push(uint256.NewInt(1))
|
||||||
stack.push(big.NewInt(0))
|
stack.push(new(uint256.Int))
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
|
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
|
||||||
if len(logger.changedValues[contract.Address()]) == 0 {
|
if len(logger.changedValues[contract.Address()]) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/holiman/uint256"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Memory implements a simple memory model for the ethereum virtual machine.
|
// 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
|
// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
|
||||||
// 32 bytes.
|
// 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.
|
// length of store may never be less than offset + size.
|
||||||
// The store should be resized PRIOR to setting the memory
|
// The store should be resized PRIOR to setting the memory
|
||||||
if offset+32 > uint64(len(m.store)) {
|
if offset+32 > uint64(len(m.store)) {
|
||||||
panic("invalid memory: store empty")
|
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
|
// 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
|
// 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) {
|
func (m *Memory) GetCopy(offset, size int64) (cpy []byte) {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -107,18 +103,3 @@ func (m *Memory) Len() int {
|
||||||
func (m *Memory) Data() []byte {
|
func (m *Memory) Data() []byte {
|
||||||
return m.store
|
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
|
package vm
|
||||||
|
|
||||||
func memorySha3(stack *Stack) (uint64, bool) {
|
func memoryKeccak256(stack *Stack) (uint64, bool) {
|
||||||
return calcMemSize64(stack.Back(0), stack.Back(1))
|
return calcMemSize64(stack.Back(0), stack.Back(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,75 +32,73 @@ func (op OpCode) IsPush() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStaticJump specifies if an opcode is JUMP.
|
|
||||||
func (op OpCode) IsStaticJump() bool {
|
|
||||||
return op == JUMP
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x0 range - arithmetic ops.
|
// 0x0 range - arithmetic ops.
|
||||||
const (
|
const (
|
||||||
STOP OpCode = iota
|
STOP OpCode = 0x0
|
||||||
ADD
|
ADD OpCode = 0x1
|
||||||
MUL
|
MUL OpCode = 0x2
|
||||||
SUB
|
SUB OpCode = 0x3
|
||||||
DIV
|
DIV OpCode = 0x4
|
||||||
SDIV
|
SDIV OpCode = 0x5
|
||||||
MOD
|
MOD OpCode = 0x6
|
||||||
SMOD
|
SMOD OpCode = 0x7
|
||||||
ADDMOD
|
ADDMOD OpCode = 0x8
|
||||||
MULMOD
|
MULMOD OpCode = 0x9
|
||||||
EXP
|
EXP OpCode = 0xa
|
||||||
SIGNEXTEND
|
SIGNEXTEND OpCode = 0xb
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x10 range - comparison ops.
|
// 0x10 range - comparison ops.
|
||||||
const (
|
const (
|
||||||
LT OpCode = iota + 0x10
|
LT OpCode = 0x10
|
||||||
GT
|
GT OpCode = 0x11
|
||||||
SLT
|
SLT OpCode = 0x12
|
||||||
SGT
|
SGT OpCode = 0x13
|
||||||
EQ
|
EQ OpCode = 0x14
|
||||||
ISZERO
|
ISZERO OpCode = 0x15
|
||||||
AND
|
AND OpCode = 0x16
|
||||||
OR
|
OR OpCode = 0x17
|
||||||
XOR
|
XOR OpCode = 0x18
|
||||||
NOT
|
NOT OpCode = 0x19
|
||||||
BYTE
|
BYTE OpCode = 0x1a
|
||||||
SHL
|
SHL OpCode = 0x1b
|
||||||
SHR
|
SHR OpCode = 0x1c
|
||||||
SAR
|
SAR OpCode = 0x1d
|
||||||
|
)
|
||||||
|
|
||||||
SHA3 OpCode = 0x20
|
// 0x20 range - crypto.
|
||||||
|
const (
|
||||||
|
KECCAK256 OpCode = 0x20
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x30 range - closure state.
|
// 0x30 range - closure state.
|
||||||
const (
|
const (
|
||||||
ADDRESS OpCode = 0x30 + iota
|
ADDRESS OpCode = 0x30
|
||||||
BALANCE
|
BALANCE OpCode = 0x31
|
||||||
ORIGIN
|
ORIGIN OpCode = 0x32
|
||||||
CALLER
|
CALLER OpCode = 0x33
|
||||||
CALLVALUE
|
CALLVALUE OpCode = 0x34
|
||||||
CALLDATALOAD
|
CALLDATALOAD OpCode = 0x35
|
||||||
CALLDATASIZE
|
CALLDATASIZE OpCode = 0x36
|
||||||
CALLDATACOPY
|
CALLDATACOPY OpCode = 0x37
|
||||||
CODESIZE
|
CODESIZE OpCode = 0x38
|
||||||
CODECOPY
|
CODECOPY OpCode = 0x39
|
||||||
GASPRICE
|
GASPRICE OpCode = 0x3a
|
||||||
EXTCODESIZE
|
EXTCODESIZE OpCode = 0x3b
|
||||||
EXTCODECOPY
|
EXTCODECOPY OpCode = 0x3c
|
||||||
RETURNDATASIZE
|
RETURNDATASIZE OpCode = 0x3d
|
||||||
RETURNDATACOPY
|
RETURNDATACOPY OpCode = 0x3e
|
||||||
EXTCODEHASH
|
EXTCODEHASH OpCode = 0x3f
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x40 range - block operations.
|
// 0x40 range - block operations.
|
||||||
const (
|
const (
|
||||||
BLOCKHASH OpCode = 0x40 + iota
|
BLOCKHASH OpCode = 0x40
|
||||||
COINBASE
|
COINBASE OpCode = 0x41
|
||||||
TIMESTAMP
|
TIMESTAMP OpCode = 0x42
|
||||||
NUMBER
|
NUMBER OpCode = 0x43
|
||||||
DIFFICULTY
|
DIFFICULTY OpCode = 0x44
|
||||||
GASLIMIT
|
GASLIMIT OpCode = 0x45
|
||||||
CHAINID OpCode = 0x46
|
CHAINID OpCode = 0x46
|
||||||
SELFBALANCE OpCode = 0x47
|
SELFBALANCE OpCode = 0x47
|
||||||
)
|
)
|
||||||
|
|
@ -121,7 +119,7 @@ const (
|
||||||
JUMPDEST
|
JUMPDEST
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x60 range.
|
// 0x60 range - pushes.
|
||||||
const (
|
const (
|
||||||
PUSH1 OpCode = 0x60 + iota
|
PUSH1 OpCode = 0x60 + iota
|
||||||
PUSH2
|
PUSH2
|
||||||
|
|
@ -155,7 +153,11 @@ const (
|
||||||
PUSH30
|
PUSH30
|
||||||
PUSH31
|
PUSH31
|
||||||
PUSH32
|
PUSH32
|
||||||
DUP1
|
)
|
||||||
|
|
||||||
|
// 0x80 range - dups.
|
||||||
|
const (
|
||||||
|
DUP1 = 0x80 + iota
|
||||||
DUP2
|
DUP2
|
||||||
DUP3
|
DUP3
|
||||||
DUP4
|
DUP4
|
||||||
|
|
@ -171,7 +173,11 @@ const (
|
||||||
DUP14
|
DUP14
|
||||||
DUP15
|
DUP15
|
||||||
DUP16
|
DUP16
|
||||||
SWAP1
|
)
|
||||||
|
|
||||||
|
// 0x90 range - swaps.
|
||||||
|
const (
|
||||||
|
SWAP1 = 0x90 + iota
|
||||||
SWAP2
|
SWAP2
|
||||||
SWAP3
|
SWAP3
|
||||||
SWAP4
|
SWAP4
|
||||||
|
|
@ -198,28 +204,22 @@ const (
|
||||||
LOG4
|
LOG4
|
||||||
)
|
)
|
||||||
|
|
||||||
// unofficial opcodes used for parsing.
|
|
||||||
const (
|
|
||||||
PUSH OpCode = 0xb0 + iota
|
|
||||||
DUP
|
|
||||||
SWAP
|
|
||||||
)
|
|
||||||
|
|
||||||
// 0xf0 range - closures.
|
// 0xf0 range - closures.
|
||||||
const (
|
const (
|
||||||
CREATE OpCode = 0xf0 + iota
|
CREATE OpCode = 0xf0
|
||||||
CALL
|
CALL OpCode = 0xf1
|
||||||
CALLCODE
|
CALLCODE OpCode = 0xf2
|
||||||
RETURN
|
RETURN OpCode = 0xf3
|
||||||
DELEGATECALL
|
DELEGATECALL OpCode = 0xf4
|
||||||
CREATE2
|
CREATE2 OpCode = 0xf5
|
||||||
|
|
||||||
STATICCALL OpCode = 0xfa
|
STATICCALL OpCode = 0xfa
|
||||||
REVERT OpCode = 0xfd
|
REVERT OpCode = 0xfd
|
||||||
|
INVALID OpCode = 0xfe
|
||||||
SELFDESTRUCT OpCode = 0xff
|
SELFDESTRUCT OpCode = 0xff
|
||||||
)
|
)
|
||||||
|
|
||||||
// Since the opcodes aren't all in order we can't use a regular slice.
|
var opCodeToString = [256]string{
|
||||||
var opCodeToString = map[OpCode]string{
|
|
||||||
// 0x0 range - arithmetic ops.
|
// 0x0 range - arithmetic ops.
|
||||||
STOP: "STOP",
|
STOP: "STOP",
|
||||||
ADD: "ADD",
|
ADD: "ADD",
|
||||||
|
|
@ -251,7 +251,7 @@ var opCodeToString = map[OpCode]string{
|
||||||
MULMOD: "MULMOD",
|
MULMOD: "MULMOD",
|
||||||
|
|
||||||
// 0x20 range - crypto.
|
// 0x20 range - crypto.
|
||||||
SHA3: "SHA3",
|
KECCAK256: "KECCAK256",
|
||||||
|
|
||||||
// 0x30 range - closure state.
|
// 0x30 range - closure state.
|
||||||
ADDRESS: "ADDRESS",
|
ADDRESS: "ADDRESS",
|
||||||
|
|
@ -379,20 +379,16 @@ var opCodeToString = map[OpCode]string{
|
||||||
CREATE2: "CREATE2",
|
CREATE2: "CREATE2",
|
||||||
STATICCALL: "STATICCALL",
|
STATICCALL: "STATICCALL",
|
||||||
REVERT: "REVERT",
|
REVERT: "REVERT",
|
||||||
|
INVALID: "INVALID",
|
||||||
SELFDESTRUCT: "SELFDESTRUCT",
|
SELFDESTRUCT: "SELFDESTRUCT",
|
||||||
|
|
||||||
PUSH: "PUSH",
|
|
||||||
DUP: "DUP",
|
|
||||||
SWAP: "SWAP",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (op OpCode) String() string {
|
func (op OpCode) String() string {
|
||||||
str := opCodeToString[op]
|
if s := opCodeToString[op]; s != "" {
|
||||||
if len(str) == 0 {
|
return s
|
||||||
return fmt.Sprintf("opcode 0x%x not defined", int(op))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return str
|
return fmt.Sprintf("opcode %#x not defined", int(op))
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringToOp = map[string]OpCode{
|
var stringToOp = map[string]OpCode{
|
||||||
|
|
@ -422,7 +418,7 @@ var stringToOp = map[string]OpCode{
|
||||||
"SAR": SAR,
|
"SAR": SAR,
|
||||||
"ADDMOD": ADDMOD,
|
"ADDMOD": ADDMOD,
|
||||||
"MULMOD": MULMOD,
|
"MULMOD": MULMOD,
|
||||||
"SHA3": SHA3,
|
"KECCAK256": KECCAK256,
|
||||||
"ADDRESS": ADDRESS,
|
"ADDRESS": ADDRESS,
|
||||||
"BALANCE": BALANCE,
|
"BALANCE": BALANCE,
|
||||||
"ORIGIN": ORIGIN,
|
"ORIGIN": ORIGIN,
|
||||||
|
|
@ -536,6 +532,7 @@ var stringToOp = map[string]OpCode{
|
||||||
"RETURN": RETURN,
|
"RETURN": RETURN,
|
||||||
"CALLCODE": CALLCODE,
|
"CALLCODE": CALLCODE,
|
||||||
"REVERT": REVERT,
|
"REVERT": REVERT,
|
||||||
|
"INVALID": INVALID,
|
||||||
"SELFDESTRUCT": SELFDESTRUCT,
|
"SELFDESTRUCT": SELFDESTRUCT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,37 +17,31 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/holiman/uint256"
|
||||||
"math/big"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stack is an object for basic stack operations. Items popped to the stack are
|
// 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
|
// expected to be changed and modified. stack does not take care of adding newly
|
||||||
// initialised objects.
|
// initialised objects.
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
data []*big.Int
|
data []uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newstack() *Stack {
|
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.
|
// Data returns the underlying uint256.Int array.
|
||||||
func (st *Stack) Data() []*big.Int {
|
func (st *Stack) Data() []uint256.Int {
|
||||||
return st.data
|
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
|
// NOTE push limit (1024) is checked in baseCheck
|
||||||
//stackItem := new(big.Int).Set(d)
|
st.data = append(st.data, *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) {
|
func (st *Stack) pop() (ret uint256.Int) {
|
||||||
ret = st.data[len(st.data)-1]
|
ret = st.data[len(st.data)-1]
|
||||||
st.data = st.data[:len(st.data)-1]
|
st.data = st.data[:len(st.data)-1]
|
||||||
return
|
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]
|
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) {
|
func (st *Stack) dup(n int) {
|
||||||
st.push(pool.get().Set(st.data[st.len()-n]))
|
st.push(&st.data[st.len()-n])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) peek() *big.Int {
|
func (st *Stack) peek() *uint256.Int {
|
||||||
return st.data[st.len()-1]
|
return &st.data[st.len()-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back returns the n'th item in stack
|
// Back returns the n'th item in stack
|
||||||
func (st *Stack) Back(n int) *big.Int {
|
func (st *Stack) Back(n int) *uint256.Int {
|
||||||
return st.data[st.len()-n-1]
|
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("#############")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
"result": {
|
"result": {
|
||||||
"calls": [
|
"calls": [
|
||||||
{
|
{
|
||||||
"error": "invalid opcode: opcode 0xfe not defined",
|
"error": "invalid opcode: INVALID",
|
||||||
"from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
|
"from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
|
||||||
"gas": "0x75fe3",
|
"gas": "0x75fe3",
|
||||||
"gasUsed": "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)
|
log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
|
||||||
return new(big.Int)
|
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
|
// 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) SetNonce(uint64) {}
|
||||||
func (account) Balance() *big.Int { return nil }
|
func (account) Balance() *big.Int { return nil }
|
||||||
func (account) Address() common.Address { return common.Address{} }
|
func (account) Address() common.Address { return common.Address{} }
|
||||||
func (account) ReturnGas(*big.Int) {}
|
|
||||||
func (account) SetCode(common.Hash, []byte) {}
|
func (account) SetCode(common.Hash, []byte) {}
|
||||||
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
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/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/golang-lru v0.5.3
|
github.com/hashicorp/golang-lru v0.5.3
|
||||||
|
github.com/holiman/uint256 v1.2.4
|
||||||
github.com/huin/goupnp v1.3.0
|
github.com/huin/goupnp v1.3.0
|
||||||
github.com/influxdata/influxdb v1.7.9
|
github.com/influxdata/influxdb v1.7.9
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
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/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
||||||
github.com/google/uuid v1.3.0 // 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/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e // 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/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 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
||||||
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
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/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 v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
||||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
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.
|
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||||
|
|
||||||
Sha3Gas uint64 = 30 // Once per SHA3 operation.
|
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
||||||
Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data.
|
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.
|
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.
|
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.
|
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
|
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
|
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
|
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.
|
SstoreSetGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
|
||||||
SstoreDirtyGasEIP2200 uint64 = 800 // Once per SSTORE operation if a dirty value is changed.
|
SstoreResetGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
|
||||||
SstoreInitGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
|
SstoreClearsScheduleRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
|
||||||
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
|
|
||||||
|
|
||||||
Create2Gas uint64 = 32000 // Once per CREATE2 operation
|
Create2Gas uint64 = 32000 // Once per CREATE2 operation
|
||||||
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
|
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core"
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"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,
|
Difficulty: t.json.Env.Difficulty,
|
||||||
GasPrice: t.json.Exec.GasPrice,
|
GasPrice: t.json.Exec.GasPrice,
|
||||||
}
|
}
|
||||||
vmconfig.NoRecursion = true
|
|
||||||
return vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig)
|
return vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue