Use interface as Copy() result

This commit is contained in:
codchen 2023-10-20 14:00:37 +08:00
parent 16a8208f36
commit d04ef5cf81
27 changed files with 753 additions and 714 deletions

View file

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
@ -684,7 +685,7 @@ func (s *StateDB) CreateAccount(addr common.Address) {
// Copy creates a deep, independent copy of the state. // Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy. // Snapshots of the copied state cannot be applied to the copy.
func (s *StateDB) Copy() *StateDB { func (s *StateDB) Copy() vm.StateDB {
// Copy all the basic fields, initialize the memory ones // Copy all the basic fields, initialize the memory ones
state := &StateDB{ state := &StateDB{
db: s.db, db: s.db,

View file

@ -181,16 +181,16 @@ func TestCopy(t *testing.T) {
// modify all in memory // modify all in memory
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) copyObj := copy.(*StateDB).GetOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.(*StateDB).GetOrNewStateObject(common.BytesToAddress([]byte{i}))
origObj.AddBalance(big.NewInt(2 * int64(i))) origObj.AddBalance(big.NewInt(2 * int64(i)))
copyObj.AddBalance(big.NewInt(3 * int64(i))) copyObj.AddBalance(big.NewInt(3 * int64(i)))
ccopyObj.AddBalance(big.NewInt(4 * int64(i))) ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
orig.updateStateObject(origObj) orig.updateStateObject(origObj)
copy.updateStateObject(copyObj) copy.(*StateDB).updateStateObject(copyObj)
ccopy.updateStateObject(copyObj) ccopy.(*StateDB).updateStateObject(copyObj)
} }
// Finalise the changes on all concurrently // Finalise the changes on all concurrently
@ -202,15 +202,15 @@ func TestCopy(t *testing.T) {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(3) wg.Add(3)
go finalise(&wg, orig) go finalise(&wg, orig)
go finalise(&wg, copy) go finalise(&wg, copy.(*StateDB))
go finalise(&wg, ccopy) go finalise(&wg, ccopy.(*StateDB))
wg.Wait() wg.Wait()
// Verify that the three states have been updated independently // Verify that the three states have been updated independently
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) copyObj := copy.(*StateDB).GetOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.(*StateDB).GetOrNewStateObject(common.BytesToAddress([]byte{i}))
if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
@ -1016,7 +1016,7 @@ func TestStateDBAccessList(t *testing.T) {
} }
// Check the copy // Check the copy
// Make a copy // Make a copy
state = stateCopy1 state = stateCopy1.(*StateDB)
verifyAddrs("aa", "bb") verifyAddrs("aa", "bb")
verifySlots("bb", "01", "02") verifySlots("bb", "01", "02")
if got, exp := len(state.accessList.addresses), 2; got != exp { if got, exp := len(state.accessList.addresses), 2; got != exp {

View file

@ -25,16 +25,16 @@ const (
set7BitsMask = uint16(0b111_1111) 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.
// An unset bit means the byte is an opcode, a set bit means // An unset bit means the byte is an opcode, a set bit means
// it's data (i.e. argument of PUSHxx). // it's data (i.e. argument of PUSHxx).
type bitvec []byte type Bitvec []byte
func (bits bitvec) set1(pos uint64) { func (bits Bitvec) set1(pos uint64) {
bits[pos/8] |= 1 << (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) bits[pos/8] |= byte(a)
if b := byte(a >> 8); b != 0 { if b := byte(a >> 8); b != 0 {
@ -42,13 +42,13 @@ func (bits bitvec) setN(flag uint16, pos uint64) {
} }
} }
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
@ -56,23 +56,23 @@ 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] >> (pos % 8)) & 1) == 0 return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
} }
// codeBitmap collects data locations in code. // CodeBitmap collects data locations in code.
func codeBitmap(code []byte) bitvec { func CodeBitmap(code []byte) Bitvec {
// The bitmap is 4 bytes longer than necessary, in case the code // The bitmap is 4 bytes longer than necessary, in case the code
// ends with a PUSH32, the algorithm will set bits on the // ends with a PUSH32, the algorithm will set bits on the
// bitvector outside the bounds of the actual code. // Bitvector outside the bounds of the actual code.
bits := make(bitvec, len(code)/8+1+4) bits := make(Bitvec, len(code)/8+1+4)
return codeBitmapInternal(code, bits) return CodeBitmapInternal(code, bits)
} }
// codeBitmapInternal is the internal implementation of codeBitmap. // CodeBitmapInternal is the internal implementation of CodeBitmap.
// It exists for the purpose of being able to run benchmark tests // It exists for the purpose of being able to run benchmark tests
// without dynamic allocations affecting the results. // without dynamic allocations affecting the results.
func codeBitmapInternal(code, bits bitvec) bitvec { func CodeBitmapInternal(code, bits Bitvec) Bitvec {
for pc := uint64(0); pc < uint64(len(code)); { for pc := uint64(0); pc < uint64(len(code)); {
op := OpCode(code[pc]) op := OpCode(code[pc])
pc++ pc++

View file

@ -14,12 +14,13 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"math/bits" "math/bits"
"testing" "testing"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
@ -29,30 +30,30 @@ func TestJumpDestAnalysis(t *testing.T) {
exp byte exp byte
which int which int
}{ }{
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0}, {[]byte{byte(vm.PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0}, {[]byte{byte(vm.PUSH1), byte(vm.PUSH1), byte(vm.PUSH1), byte(vm.PUSH1)}, 0b0000_1010, 0},
{[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0}, {[]byte{0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1)}, 0b0101_0100, 0},
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0}, {[]byte{byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), byte(vm.PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0},
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1}, {[]byte{byte(vm.PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0}, {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(vm.PUSH2), byte(vm.PUSH2), byte(vm.PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1}, {[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(vm.PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0}, {[]byte{byte(vm.PUSH3), 0x01, 0x01, 0x01, byte(vm.PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1}, {[]byte{byte(vm.PUSH3), 0x01, 0x01, 0x01, byte(vm.PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0}, {[]byte{0x01, byte(vm.PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1}, {[]byte{0x01, byte(vm.PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0}, {[]byte{byte(vm.PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1}, {[]byte{byte(vm.PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2}, {[]byte{byte(vm.PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0}, {[]byte{byte(vm.PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(vm.PUSH1), 0x01}, 0b1111_1110, 0},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1}, {[]byte{byte(vm.PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(vm.PUSH1), 0x01}, 0b0000_0101, 1},
{[]byte{byte(PUSH32)}, 0b1111_1110, 0}, {[]byte{byte(vm.PUSH32)}, 0b1111_1110, 0},
{[]byte{byte(PUSH32)}, 0b1111_1111, 1}, {[]byte{byte(vm.PUSH32)}, 0b1111_1111, 1},
{[]byte{byte(PUSH32)}, 0b1111_1111, 2}, {[]byte{byte(vm.PUSH32)}, 0b1111_1111, 2},
{[]byte{byte(PUSH32)}, 0b1111_1111, 3}, {[]byte{byte(vm.PUSH32)}, 0b1111_1111, 3},
{[]byte{byte(PUSH32)}, 0b0000_0001, 4}, {[]byte{byte(vm.PUSH32)}, 0b0000_0001, 4},
} }
for i, test := range tests { for i, test := range tests {
ret := codeBitmap(test.code) ret := vm.CodeBitmap(test.code)
if ret[test.which] != test.exp { if ret[test.which] != test.exp {
t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which]) t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which])
} }
@ -67,7 +68,7 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
bench.SetBytes(analysisCodeSize) bench.SetBytes(analysisCodeSize)
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
codeBitmap(code) vm.CodeBitmap(code)
} }
bench.StopTimer() bench.StopTimer()
} }
@ -83,27 +84,27 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
} }
func BenchmarkJumpdestOpAnalysis(bench *testing.B) { func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
var op OpCode var op vm.OpCode
bencher := func(b *testing.B) { bencher := func(b *testing.B) {
code := make([]byte, analysisCodeSize) code := make([]byte, analysisCodeSize)
b.SetBytes(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(vm.Bitvec, len(code)/8+1+4)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
for j := range bits { for j := range bits {
bits[j] = 0 bits[j] = 0
} }
codeBitmapInternal(code, bits) vm.CodeBitmapInternal(code, bits)
} }
} }
for op = PUSH1; op <= PUSH32; op++ { for op = vm.PUSH1; op <= vm.PUSH32; op++ {
bench.Run(op.String(), bencher) bench.Run(op.String(), bencher)
} }
op = JUMPDEST op = vm.JUMPDEST
bench.Run(op.String(), bencher) bench.Run(op.String(), bencher)
op = STOP op = vm.STOP
bench.Run(op.String(), bencher) bench.Run(op.String(), bencher)
} }

View file

@ -63,8 +63,8 @@ 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))
} }
// 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 {
return math.MaxUint64/32 + 1 return math.MaxUint64/32 + 1
} }

View file

@ -50,8 +50,8 @@ type Contract struct {
caller ContractRef caller ContractRef
self ContractRef self ContractRef
jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. jumpdests map[common.Hash]Bitvec // Aggregated result of JUMPDEST analysis.
analysis bitvec // Locally cached result of JUMPDEST analysis analysis Bitvec // Locally cached result of JUMPDEST analysis
Code []byte Code []byte
CodeHash common.Hash CodeHash common.Hash
@ -70,7 +70,7 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
// Reuse JUMPDEST analysis from parent context if available. // Reuse JUMPDEST analysis from parent context if available.
c.jumpdests = parent.jumpdests c.jumpdests = parent.jumpdests
} else { } else {
c.jumpdests = make(map[common.Hash]bitvec) c.jumpdests = make(map[common.Hash]Bitvec)
} }
// Gas should be a pointer so it can safely be reduced through the run // Gas should be a pointer so it can safely be reduced through the run
@ -112,7 +112,7 @@ func (c *Contract) isCode(udest uint64) bool {
if !exist { if !exist {
// Do the analysis and save in parent context // Do the analysis and save in parent context
// We do not need to store it in c.analysis // We do not need to store it in c.analysis
analysis = codeBitmap(c.Code) analysis = CodeBitmap(c.Code)
c.jumpdests[c.CodeHash] = analysis c.jumpdests[c.CodeHash] = analysis
} }
// Also stash it in current contract for faster access // Also stash it in current contract for faster access
@ -124,7 +124,7 @@ func (c *Contract) isCode(udest uint64) bool {
// we don't have to recalculate it for every JUMP instruction in the execution // we don't have to recalculate it for every JUMP instruction in the execution
// However, we don't save it within the parent context // However, we don't save it within the parent context
if c.analysis == nil { if c.analysis == nil {
c.analysis = codeBitmap(c.Code) c.analysis = CodeBitmap(c.Code)
} }
return c.analysis.codeSegment(udest) return c.analysis.codeSegment(udest)
} }

View file

@ -26,8 +26,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
bls12381 "github.com/ethereum/go-ethereum/crypto/Bls12381"
"github.com/ethereum/go-ethereum/crypto/blake2b" "github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bls12381"
"github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -45,20 +45,20 @@ type PrecompiledContract interface {
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
// contracts used in the Frontier and Homestead releases. // contracts used in the Frontier and Homestead releases.
var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &DataCopy{},
} }
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum // PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release. // contracts used in the Byzantium release.
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &DataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, common.BytesToAddress([]byte{5}): &BigModExp{Eip2565: false},
common.BytesToAddress([]byte{6}): &bn256AddByzantium{}, common.BytesToAddress([]byte{6}): &bn256AddByzantium{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{}, common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{},
common.BytesToAddress([]byte{8}): &bn256PairingByzantium{}, common.BytesToAddress([]byte{8}): &bn256PairingByzantium{},
@ -67,58 +67,58 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum // PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release. // contracts used in the Istanbul release.
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &DataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, common.BytesToAddress([]byte{5}): &BigModExp{Eip2565: false},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{6}): &Bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{7}): &Bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{8}): &Bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{9}): &Blake2F{},
} }
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release. // contracts used in the Berlin release.
var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &DataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true}, common.BytesToAddress([]byte{5}): &BigModExp{Eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{6}): &Bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{7}): &Bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{8}): &Bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{9}): &Blake2F{},
} }
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum // PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
// contracts used in the Cancun release. // contracts used in the Cancun release.
var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &DataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true}, common.BytesToAddress([]byte{5}): &BigModExp{Eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{6}): &Bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{7}): &Bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{8}): &Bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{9}): &Blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, common.BytesToAddress([]byte{0x0a}): &KzgPointEvaluation{},
} }
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum // PrecompiledContractsBLS contains the set of pre-compiled Ethereum
// contracts specified in EIP-2537. These are exported for testing purposes. // contracts specified in EIP-2537. These are exported for testing purposes.
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{10}): &bls12381G1Add{}, common.BytesToAddress([]byte{10}): &Bls12381G1Add{},
common.BytesToAddress([]byte{11}): &bls12381G1Mul{}, common.BytesToAddress([]byte{11}): &Bls12381G1Mul{},
common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{}, common.BytesToAddress([]byte{12}): &Bls12381G1MultiExp{},
common.BytesToAddress([]byte{13}): &bls12381G2Add{}, common.BytesToAddress([]byte{13}): &Bls12381G2Add{},
common.BytesToAddress([]byte{14}): &bls12381G2Mul{}, common.BytesToAddress([]byte{14}): &Bls12381G2Mul{},
common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{}, common.BytesToAddress([]byte{15}): &Bls12381G2MultiExp{},
common.BytesToAddress([]byte{16}): &bls12381Pairing{}, common.BytesToAddress([]byte{16}): &Bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{}, common.BytesToAddress([]byte{17}): &Bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{}, common.BytesToAddress([]byte{18}): &Bls12381MapG2{},
} }
var ( var (
@ -179,18 +179,18 @@ func RunPrecompiledContract(p PrecompiledContract, evm *EVM, input []byte, suppl
} }
// ECRECOVER implemented as a native contract. // ECRECOVER implemented as a native contract.
type ecrecover struct{} type Ecrecover struct{}
func (c *ecrecover) RequiredGas(input []byte) uint64 { func (c *Ecrecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas return params.EcrecoverGas
} }
func (c *ecrecover) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Ecrecover) Run(_ *EVM, input []byte) ([]byte, error) {
const ecRecoverInputLength = 128 const ecRecoverInputLength = 128
input = common.RightPadBytes(input, ecRecoverInputLength) input = common.RightPadBytes(input, ecRecoverInputLength)
// "input" is (hash, v, r, s), each 32 bytes // "input" is (hash, v, r, s), each 32 bytes
// but for ecrecover we want (r, s, v) // but for Ecrecover we want (r, s, v)
r := new(big.Int).SetBytes(input[64:96]) r := new(big.Int).SetBytes(input[64:96])
s := new(big.Int).SetBytes(input[96:128]) s := new(big.Int).SetBytes(input[96:128])
@ -217,53 +217,53 @@ func (c *ecrecover) Run(_ *EVM, input []byte) ([]byte, error) {
} }
// SHA256 implemented as a native contract. // SHA256 implemented as a native contract.
type sha256hash struct{} type Sha256hash struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
// //
// This method does not require any overflow checking as the input size gas costs // This method does not require any overflow checking as the input size gas costs
// required for anything significant is so high it's impossible to pay for. // required for anything significant is so high it's impossible to pay for.
func (c *sha256hash) RequiredGas(input []byte) uint64 { func (c *Sha256hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
} }
func (c *sha256hash) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Sha256hash) Run(_ *EVM, input []byte) ([]byte, error) {
h := sha256.Sum256(input) h := sha256.Sum256(input)
return h[:], nil return h[:], nil
} }
// RIPEMD160 implemented as a native contract. // RIPEMD160 implemented as a native contract.
type ripemd160hash struct{} type Ripemd160hash struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
// //
// This method does not require any overflow checking as the input size gas costs // This method does not require any overflow checking as the input size gas costs
// required for anything significant is so high it's impossible to pay for. // required for anything significant is so high it's impossible to pay for.
func (c *ripemd160hash) RequiredGas(input []byte) uint64 { func (c *Ripemd160hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
} }
func (c *ripemd160hash) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Ripemd160hash) Run(_ *EVM, input []byte) ([]byte, error) {
ripemd := ripemd160.New() ripemd := ripemd160.New()
ripemd.Write(input) ripemd.Write(input)
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
} }
// data copy implemented as a native contract. // data copy implemented as a native contract.
type dataCopy struct{} type DataCopy struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
// //
// This method does not require any overflow checking as the input size gas costs // This method does not require any overflow checking as the input size gas costs
// required for anything significant is so high it's impossible to pay for. // required for anything significant is so high it's impossible to pay for.
func (c *dataCopy) RequiredGas(input []byte) uint64 { func (c *DataCopy) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
} }
func (c *dataCopy) Run(_ *EVM, in []byte) ([]byte, error) { func (c *DataCopy) Run(_ *EVM, in []byte) ([]byte, error) {
return common.CopyBytes(in), nil return common.CopyBytes(in), nil
} }
// bigModExp implements a native big integer exponential modular operation. // BigModExp implements a native big integer exponential modular operation.
type bigModExp struct { type BigModExp struct {
eip2565 bool Eip2565 bool
} }
var ( var (
@ -313,7 +313,7 @@ func modexpMultComplexity(x *big.Int) *big.Int {
} }
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bigModExp) RequiredGas(input []byte) uint64 { func (c *BigModExp) RequiredGas(input []byte) uint64 {
var ( var (
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
expLen = new(big.Int).SetBytes(getData(input, 32, 32)) expLen = new(big.Int).SetBytes(getData(input, 32, 32))
@ -348,7 +348,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
// Calculate the gas cost of the operation // Calculate the gas cost of the operation
gas := new(big.Int).Set(math.BigMax(modLen, baseLen)) gas := new(big.Int).Set(math.BigMax(modLen, baseLen))
if c.eip2565 { if c.Eip2565 {
// EIP-2565 has three changes // EIP-2565 has three changes
// 1. Different multComplexity (inlined here) // 1. Different multComplexity (inlined here)
// in EIP-2565 (https://eips.ethereum.org/EIPS/eip-2565): // in EIP-2565 (https://eips.ethereum.org/EIPS/eip-2565):
@ -383,7 +383,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
return gas.Uint64() return gas.Uint64()
} }
func (c *bigModExp) Run(_ *EVM, input []byte) ([]byte, error) { func (c *BigModExp) Run(_ *EVM, input []byte) ([]byte, error) {
var ( var (
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
@ -456,14 +456,14 @@ func runBn256Add(input []byte) ([]byte, error) {
// bn256Add implements a native elliptic curve point addition conforming to // bn256Add implements a native elliptic curve point addition conforming to
// Istanbul consensus rules. // Istanbul consensus rules.
type bn256AddIstanbul struct{} type Bn256AddIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { func (c *Bn256AddIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasIstanbul return params.Bn256AddGasIstanbul
} }
func (c *bn256AddIstanbul) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bn256AddIstanbul) Run(_ *EVM, input []byte) ([]byte, error) {
return runBn256Add(input) return runBn256Add(input)
} }
@ -492,16 +492,16 @@ func runBn256ScalarMul(input []byte) ([]byte, error) {
return res.Marshal(), nil return res.Marshal(), nil
} }
// bn256ScalarMulIstanbul implements a native elliptic curve scalar // Bn256ScalarMulIstanbul implements a native elliptic curve scalar
// multiplication conforming to Istanbul consensus rules. // multiplication conforming to Istanbul consensus rules.
type bn256ScalarMulIstanbul struct{} type Bn256ScalarMulIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { func (c *Bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasIstanbul return params.Bn256ScalarMulGasIstanbul
} }
func (c *bn256ScalarMulIstanbul) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bn256ScalarMulIstanbul) Run(_ *EVM, input []byte) ([]byte, error) {
return runBn256ScalarMul(input) return runBn256ScalarMul(input)
} }
@ -560,16 +560,16 @@ func runBn256Pairing(input []byte) ([]byte, error) {
return false32Byte, nil return false32Byte, nil
} }
// bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve // Bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve
// conforming to Istanbul consensus rules. // conforming to Istanbul consensus rules.
type bn256PairingIstanbul struct{} type Bn256PairingIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { func (c *Bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
} }
func (c *bn256PairingIstanbul) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bn256PairingIstanbul) Run(_ *EVM, input []byte) ([]byte, error) {
return runBn256Pairing(input) return runBn256Pairing(input)
} }
@ -586,40 +586,40 @@ func (c *bn256PairingByzantium) Run(_ *EVM, input []byte) ([]byte, error) {
return runBn256Pairing(input) return runBn256Pairing(input)
} }
type blake2F struct{} type Blake2F struct{}
func (c *blake2F) RequiredGas(input []byte) uint64 { func (c *Blake2F) RequiredGas(input []byte) uint64 {
// If the input is malformed, we can't calculate the gas, return 0 and let the // If the input is malformed, we can't calculate the gas, return 0 and let the
// actual call choke and fault. // actual call choke and fault.
if len(input) != blake2FInputLength { if len(input) != Blake2FInputLength {
return 0 return 0
} }
return uint64(binary.BigEndian.Uint32(input[0:4])) return uint64(binary.BigEndian.Uint32(input[0:4]))
} }
const ( const (
blake2FInputLength = 213 Blake2FInputLength = 213
blake2FFinalBlockBytes = byte(1) Blake2FFinalBlockBytes = byte(1)
blake2FNonFinalBlockBytes = byte(0) Blake2FNonFinalBlockBytes = byte(0)
) )
var ( var (
errBlake2FInvalidInputLength = errors.New("invalid input length") ErrBlake2FInvalidInputLength = errors.New("invalid input length")
errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ErrBlake2FInvalidFinalFlag = errors.New("invalid final flag")
) )
func (c *blake2F) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Blake2F) Run(_ *EVM, input []byte) ([]byte, error) {
// Make sure the input is valid (correct length and final flag) // Make sure the input is valid (correct length and final flag)
if len(input) != blake2FInputLength { if len(input) != Blake2FInputLength {
return nil, errBlake2FInvalidInputLength return nil, ErrBlake2FInvalidInputLength
} }
if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes { if input[212] != Blake2FNonFinalBlockBytes && input[212] != Blake2FFinalBlockBytes {
return nil, errBlake2FInvalidFinalFlag return nil, ErrBlake2FInvalidFinalFlag
} }
// 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
@ -649,20 +649,20 @@ func (c *blake2F) Run(_ *EVM, input []byte) ([]byte, error) {
var ( var (
errBLS12381InvalidInputLength = errors.New("invalid input length") errBLS12381InvalidInputLength = errors.New("invalid input length")
errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes") errBLS12381InvalidFieldElementTOpBytes = errors.New("invalid field element top bytes")
errBLS12381G1PointSubgroup = errors.New("g1 point is not on correct subgroup") errBLS12381G1PointSubgroup = errors.New("g1 point is not on correct subgroup")
errBLS12381G2PointSubgroup = errors.New("g2 point is not on correct subgroup") errBLS12381G2PointSubgroup = errors.New("g2 point is not on correct subgroup")
) )
// bls12381G1Add implements EIP-2537 G1Add precompile. // Bls12381G1Add implements EIP-2537 G1Add precompile.
type bls12381G1Add struct{} type Bls12381G1Add struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { func (c *Bls12381G1Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G1AddGas return params.Bls12381G1AddGas
} }
func (c *bls12381G1Add) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G1Add) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G1Add precompile. // Implements EIP-2537 G1Add precompile.
// > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
// > Output is an encoding of addition operation result - single G1 point (`128` bytes). // > Output is an encoding of addition operation result - single G1 point (`128` bytes).
@ -692,15 +692,15 @@ func (c *bls12381G1Add) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381G1Mul implements EIP-2537 G1Mul precompile. // Bls12381G1Mul implements EIP-2537 G1Mul precompile.
type bls12381G1Mul struct{} type Bls12381G1Mul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { func (c *Bls12381G1Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G1MulGas return params.Bls12381G1MulGas
} }
func (c *bls12381G1Mul) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G1Mul) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G1Mul precompile. // Implements EIP-2537 G1Mul precompile.
// > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes).
@ -728,11 +728,11 @@ func (c *bls12381G1Mul) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. // Bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
type bls12381G1MultiExp struct{} type Bls12381G1MultiExp struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { func (c *Bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G1 point, scalar value pair length // Calculate G1 point, scalar value pair length
k := len(input) / 160 k := len(input) / 160
if k == 0 { if k == 0 {
@ -750,7 +750,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
} }
func (c *bls12381G1MultiExp) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G1MultiExp) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G1MultiExp precompile. // Implements EIP-2537 G1MultiExp precompile.
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
@ -785,15 +785,15 @@ func (c *bls12381G1MultiExp) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381G2Add implements EIP-2537 G2Add precompile. // Bls12381G2Add implements EIP-2537 G2Add precompile.
type bls12381G2Add struct{} type Bls12381G2Add struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { func (c *Bls12381G2Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G2AddGas return params.Bls12381G2AddGas
} }
func (c *bls12381G2Add) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G2Add) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G2Add precompile. // Implements EIP-2537 G2Add precompile.
// > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
// > Output is an encoding of addition operation result - single G2 point (`256` bytes). // > Output is an encoding of addition operation result - single G2 point (`256` bytes).
@ -823,15 +823,15 @@ func (c *bls12381G2Add) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381G2Mul implements EIP-2537 G2Mul precompile. // Bls12381G2Mul implements EIP-2537 G2Mul precompile.
type bls12381G2Mul struct{} type Bls12381G2Mul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { func (c *Bls12381G2Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G2MulGas return params.Bls12381G2MulGas
} }
func (c *bls12381G2Mul) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G2Mul) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G2MUL precompile logic. // Implements EIP-2537 G2MUL precompile logic.
// > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes).
@ -859,11 +859,11 @@ func (c *bls12381G2Mul) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. // Bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
type bls12381G2MultiExp struct{} type Bls12381G2MultiExp struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { func (c *Bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G2 point, scalar value pair length // Calculate G2 point, scalar value pair length
k := len(input) / 288 k := len(input) / 288
if k == 0 { if k == 0 {
@ -881,7 +881,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
} }
func (c *bls12381G2MultiExp) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381G2MultiExp) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 G2MultiExp precompile logic // Implements EIP-2537 G2MultiExp precompile logic
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
@ -916,15 +916,15 @@ func (c *bls12381G2MultiExp) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381Pairing implements EIP-2537 Pairing precompile. // Bls12381Pairing implements EIP-2537 Pairing precompile.
type bls12381Pairing struct{} type Bls12381Pairing struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { func (c *Bls12381Pairing) RequiredGas(input []byte) uint64 {
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
} }
func (c *bls12381Pairing) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381Pairing) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 Pairing precompile logic. // Implements EIP-2537 Pairing precompile logic.
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
// > - `128` bytes of G1 point encoding // > - `128` bytes of G1 point encoding
@ -987,7 +987,7 @@ func decodeBLS12381FieldElement(in []byte) ([]byte, error) {
// check top bytes // check top bytes
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
if in[i] != byte(0x00) { if in[i] != byte(0x00) {
return nil, errBLS12381InvalidFieldElementTopBytes return nil, errBLS12381InvalidFieldElementTOpBytes
} }
} }
out := make([]byte, 48) out := make([]byte, 48)
@ -995,15 +995,15 @@ func decodeBLS12381FieldElement(in []byte) ([]byte, error) {
return out, nil return out, nil
} }
// bls12381MapG1 implements EIP-2537 MapG1 precompile. // Bls12381MapG1 implements EIP-2537 MapG1 precompile.
type bls12381MapG1 struct{} type Bls12381MapG1 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { func (c *Bls12381MapG1) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG1Gas return params.Bls12381MapG1Gas
} }
func (c *bls12381MapG1) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381MapG1) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 Map_To_G1 precompile. // Implements EIP-2537 Map_To_G1 precompile.
// > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field.
// > Output of this call is `128` bytes and is G1 point following respective encoding rules. // > Output of this call is `128` bytes and is G1 point following respective encoding rules.
@ -1030,15 +1030,15 @@ func (c *bls12381MapG1) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// bls12381MapG2 implements EIP-2537 MapG2 precompile. // Bls12381MapG2 implements EIP-2537 MapG2 precompile.
type bls12381MapG2 struct{} type Bls12381MapG2 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract. // RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { func (c *Bls12381MapG2) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG2Gas return params.Bls12381MapG2Gas
} }
func (c *bls12381MapG2) Run(_ *EVM, input []byte) ([]byte, error) { func (c *Bls12381MapG2) Run(_ *EVM, input []byte) ([]byte, error) {
// Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
// > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field.
// > Output of this call is `256` bytes and is G2 point following respective encoding rules. // > Output of this call is `256` bytes and is G2 point following respective encoding rules.
@ -1072,11 +1072,11 @@ func (c *bls12381MapG2) Run(_ *EVM, input []byte) ([]byte, error) {
return g.EncodePoint(r), nil return g.EncodePoint(r), nil
} }
// kzgPointEvaluation implements the EIP-4844 point evaluation precompile. // KzgPointEvaluation implements the EIP-4844 point evaluation precompile.
type kzgPointEvaluation struct{} type KzgPointEvaluation struct{}
// RequiredGas estimates the gas required for running the point evaluation precompile. // RequiredGas estimates the gas required for running the point evaluation precompile.
func (b *kzgPointEvaluation) RequiredGas(input []byte) uint64 { func (b *KzgPointEvaluation) RequiredGas(input []byte) uint64 {
return params.BlobTxPointEvaluationPrecompileGas return params.BlobTxPointEvaluationPrecompileGas
} }
@ -1093,7 +1093,7 @@ var (
) )
// Run executes the point evaluation precompile. // Run executes the point evaluation precompile.
func (b *kzgPointEvaluation) Run(_ *EVM, input []byte) ([]byte, error) { func (b *KzgPointEvaluation) Run(_ *EVM, input []byte) ([]byte, error) {
if len(input) != blobVerifyInputLength { if len(input) != blobVerifyInputLength {
return nil, errBlobVerifyInvalidInputLength return nil, errBlobVerifyInvalidInputLength
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"bytes" "bytes"
@ -25,6 +25,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
) )
// precompiledTest defines the input/output pairs for precompiled contract tests. // precompiledTest defines the input/output pairs for precompiled contract tests.
@ -45,50 +46,50 @@ type precompiledFailureTest struct {
// allPrecompiles does not map to the actual set of precompiles, as it also contains // allPrecompiles does not map to the actual set of precompiles, as it also contains
// repriced versions of precompiles at certain slots // repriced versions of precompiles at certain slots
var allPrecompiles = map[common.Address]PrecompiledContract{ var allPrecompiles = map[common.Address]vm.PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{1}): &vm.Ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{2}): &vm.Sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{3}): &vm.Ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{4}): &vm.DataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, common.BytesToAddress([]byte{5}): &vm.BigModExp{Eip2565: false},
common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true}, common.BytesToAddress([]byte{0xf5}): &vm.BigModExp{Eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{6}): &vm.Bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{7}): &vm.Bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{8}): &vm.Bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{9}): &vm.Blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, common.BytesToAddress([]byte{0x0a}): &vm.KzgPointEvaluation{},
common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{}, common.BytesToAddress([]byte{0x0f, 0x0a}): &vm.Bls12381G1Add{},
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{}, common.BytesToAddress([]byte{0x0f, 0x0b}): &vm.Bls12381G1Mul{},
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{}, common.BytesToAddress([]byte{0x0f, 0x0c}): &vm.Bls12381G1MultiExp{},
common.BytesToAddress([]byte{0x0f, 0x0d}): &bls12381G2Add{}, common.BytesToAddress([]byte{0x0f, 0x0d}): &vm.Bls12381G2Add{},
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381G2Mul{}, common.BytesToAddress([]byte{0x0f, 0x0e}): &vm.Bls12381G2Mul{},
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381G2MultiExp{}, common.BytesToAddress([]byte{0x0f, 0x0f}): &vm.Bls12381G2MultiExp{},
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381Pairing{}, common.BytesToAddress([]byte{0x0f, 0x10}): &vm.Bls12381Pairing{},
common.BytesToAddress([]byte{0x0f, 0x11}): &bls12381MapG1{}, common.BytesToAddress([]byte{0x0f, 0x11}): &vm.Bls12381MapG1{},
common.BytesToAddress([]byte{0x0f, 0x12}): &bls12381MapG2{}, common.BytesToAddress([]byte{0x0f, 0x12}): &vm.Bls12381MapG2{},
} }
// EIP-152 test vectors // EIP-152 test vectors
var blake2FMalformedInputTests = []precompiledFailureTest{ var Blake2FMalformedInputTests = []precompiledFailureTest{
{ {
Input: "", Input: "",
ExpectedError: errBlake2FInvalidInputLength.Error(), ExpectedError: vm.ErrBlake2FInvalidInputLength.Error(),
Name: "vector 0: empty input", Name: "vector 0: empty input",
}, },
{ {
Input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", Input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
ExpectedError: errBlake2FInvalidInputLength.Error(), ExpectedError: vm.ErrBlake2FInvalidInputLength.Error(),
Name: "vector 1: less than 213 bytes input", Name: "vector 1: less than 213 bytes input",
}, },
{ {
Input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", Input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
ExpectedError: errBlake2FInvalidInputLength.Error(), ExpectedError: vm.ErrBlake2FInvalidInputLength.Error(),
Name: "vector 2: more than 213 bytes input", Name: "vector 2: more than 213 bytes input",
}, },
{ {
Input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", Input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
ExpectedError: errBlake2FInvalidFinalFlag.Error(), ExpectedError: vm.ErrBlake2FInvalidFinalFlag.Error(),
Name: "vector 3: malformed final block indicator flag", Name: "vector 3: malformed final block indicator flag",
}, },
} }
@ -98,7 +99,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
in := common.Hex2Bytes(test.Input) in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in) gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
if res, _, err := RunPrecompiledContract(p, nil, in, gas); err != nil { if res, _, err := vm.RunPrecompiledContract(p, nil, in, gas); err != nil {
t.Error(err) t.Error(err)
} else if common.Bytes2Hex(res) != test.Expected { } else if common.Bytes2Hex(res) != test.Expected {
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
@ -120,7 +121,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
gas := p.RequiredGas(in) - 1 gas := p.RequiredGas(in) - 1
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
_, _, err := RunPrecompiledContract(p, nil, in, gas) _, _, err := vm.RunPrecompiledContract(p, nil, in, gas)
if err.Error() != "out of gas" { if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err) t.Errorf("Expected error [out of gas], got [%v]", err)
} }
@ -137,7 +138,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
in := common.Hex2Bytes(test.Input) in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in) gas := p.RequiredGas(in)
t.Run(test.Name, func(t *testing.T) { t.Run(test.Name, func(t *testing.T) {
_, _, err := RunPrecompiledContract(p, nil, in, gas) _, _, err := vm.RunPrecompiledContract(p, nil, in, gas)
if err.Error() != test.ExpectedError { if err.Error() != test.ExpectedError {
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
} }
@ -169,7 +170,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
copy(data, in) copy(data, in)
res, _, err = RunPrecompiledContract(p, nil, data, reqGas) res, _, err = vm.RunPrecompiledContract(p, nil, data, reqGas)
} }
bench.StopTimer() bench.StopTimer()
elapsed := uint64(time.Since(start)) elapsed := uint64(time.Since(start))
@ -237,8 +238,8 @@ func BenchmarkPrecompiledIdentity(bench *testing.B) {
func TestPrecompiledModExp(t *testing.T) { testJson("modexp", "05", t) } func TestPrecompiledModExp(t *testing.T) { testJson("modexp", "05", t) }
func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) } func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
func TestPrecompiledModExpEip2565(t *testing.T) { testJson("modexp_eip2565", "f5", t) } func TestPrecompiledModExpEip2565(t *testing.T) { testJson("modexp_Eip2565", "f5", t) }
func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) } func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_Eip2565", "f5", b) }
// Tests the sample inputs from the elliptic curve addition EIP 213. // Tests the sample inputs from the elliptic curve addition EIP 213.
func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) } func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) }
@ -263,11 +264,11 @@ func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMu
func TestPrecompiledBn256Pairing(t *testing.T) { testJson("bn256Pairing", "08", t) } func TestPrecompiledBn256Pairing(t *testing.T) { testJson("bn256Pairing", "08", t) }
func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) } func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) }
func TestPrecompiledBlake2F(t *testing.T) { testJson("blake2F", "09", t) } func TestPrecompiledBlake2F(t *testing.T) { testJson("Blake2F", "09", t) }
func BenchmarkPrecompiledBlake2F(b *testing.B) { benchJson("blake2F", "09", b) } func BenchmarkPrecompiledBlake2F(b *testing.B) { benchJson("Blake2F", "09", b) }
func TestPrecompileBlake2FMalformedInput(t *testing.T) { func TestPrecompileBlake2FMalformedInput(t *testing.T) {
for _, test := range blake2FMalformedInputTests { for _, test := range Blake2FMalformedInputTests {
testPrecompiledFailure("09", test, t) testPrecompiledFailure("09", test, t)
} }
} }

View file

@ -71,14 +71,14 @@ func ActivateableEips() []string {
// - Define SELFBALANCE, with cost GasFastStep (5) // - Define SELFBALANCE, with cost GasFastStep (5)
func enable1884(jt *JumpTable) { func enable1884(jt *JumpTable) {
// Gas cost changes // Gas cost changes
jt[SLOAD].constantGas = params.SloadGasEIP1884 jt[SLOAD].ConstantGas = params.SloadGasEIP1884
jt[BALANCE].constantGas = params.BalanceGasEIP1884 jt[BALANCE].ConstantGas = params.BalanceGasEIP1884
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),
} }
@ -96,7 +96,7 @@ 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),
} }
@ -111,7 +111,7 @@ func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
// enable2200 applies EIP-2200 (Rebalance net-metered SSTORE) // enable2200 applies EIP-2200 (Rebalance net-metered SSTORE)
func enable2200(jt *JumpTable) { func enable2200(jt *JumpTable) {
jt[SLOAD].constantGas = params.SloadGasEIP2200 jt[SLOAD].ConstantGas = params.SloadGasEIP2200
jt[SSTORE].dynamicGas = gasSStoreEIP2200 jt[SSTORE].dynamicGas = gasSStoreEIP2200
} }
@ -120,36 +120,36 @@ func enable2200(jt *JumpTable) {
func enable2929(jt *JumpTable) { func enable2929(jt *JumpTable) {
jt[SSTORE].dynamicGas = gasSStoreEIP2929 jt[SSTORE].dynamicGas = gasSStoreEIP2929
jt[SLOAD].constantGas = 0 jt[SLOAD].ConstantGas = 0
jt[SLOAD].dynamicGas = gasSLoadEIP2929 jt[SLOAD].dynamicGas = gasSLoadEIP2929
jt[EXTCODECOPY].constantGas = params.WarmStorageReadCostEIP2929 jt[EXTCODECOPY].ConstantGas = params.WarmStorageReadCostEIP2929
jt[EXTCODECOPY].dynamicGas = gasExtCodeCopyEIP2929 jt[EXTCODECOPY].dynamicGas = gasExtCodeCopyEIP2929
jt[EXTCODESIZE].constantGas = params.WarmStorageReadCostEIP2929 jt[EXTCODESIZE].ConstantGas = params.WarmStorageReadCostEIP2929
jt[EXTCODESIZE].dynamicGas = gasEip2929AccountCheck jt[EXTCODESIZE].dynamicGas = gasEip2929AccountCheck
jt[EXTCODEHASH].constantGas = params.WarmStorageReadCostEIP2929 jt[EXTCODEHASH].ConstantGas = params.WarmStorageReadCostEIP2929
jt[EXTCODEHASH].dynamicGas = gasEip2929AccountCheck jt[EXTCODEHASH].dynamicGas = gasEip2929AccountCheck
jt[BALANCE].constantGas = params.WarmStorageReadCostEIP2929 jt[BALANCE].ConstantGas = params.WarmStorageReadCostEIP2929
jt[BALANCE].dynamicGas = gasEip2929AccountCheck jt[BALANCE].dynamicGas = gasEip2929AccountCheck
jt[CALL].constantGas = params.WarmStorageReadCostEIP2929 jt[CALL].ConstantGas = params.WarmStorageReadCostEIP2929
jt[CALL].dynamicGas = gasCallEIP2929 jt[CALL].dynamicGas = gasCallEIP2929
jt[CALLCODE].constantGas = params.WarmStorageReadCostEIP2929 jt[CALLCODE].ConstantGas = params.WarmStorageReadCostEIP2929
jt[CALLCODE].dynamicGas = gasCallCodeEIP2929 jt[CALLCODE].dynamicGas = gasCallCodeEIP2929
jt[STATICCALL].constantGas = params.WarmStorageReadCostEIP2929 jt[STATICCALL].ConstantGas = params.WarmStorageReadCostEIP2929
jt[STATICCALL].dynamicGas = gasStaticCallEIP2929 jt[STATICCALL].dynamicGas = gasStaticCallEIP2929
jt[DELEGATECALL].constantGas = params.WarmStorageReadCostEIP2929 jt[DELEGATECALL].ConstantGas = params.WarmStorageReadCostEIP2929
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP2929 jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP2929
// This was previously part of the dynamic cost, but we're using it as a constantGas // This was previously part of the dynamic cost, but we're using it as a ConstantGas
// factor here // factor here
jt[SELFDESTRUCT].constantGas = params.SelfdestructGasEIP150 jt[SELFDESTRUCT].ConstantGas = params.SelfdestructGasEIP150
jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP2929 jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP2929
} }
@ -168,7 +168,7 @@ func enable3198(jt *JumpTable) {
// New opcode // New opcode
jt[BASEFEE] = &operation{ jt[BASEFEE] = &operation{
execute: opBaseFee, execute: opBaseFee,
constantGas: GasQuickStep, ConstantGas: GasQuickStep,
minStack: minStack(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1), maxStack: maxStack(0, 1),
} }
@ -179,22 +179,22 @@ func enable3198(jt *JumpTable) {
// - Adds TSTORE that writes to transient storage // - Adds TSTORE that writes to transient storage
func enable1153(jt *JumpTable) { func enable1153(jt *JumpTable) {
jt[TLOAD] = &operation{ jt[TLOAD] = &operation{
execute: opTload, execute: OpTload,
constantGas: params.WarmStorageReadCostEIP2929, ConstantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1), maxStack: maxStack(1, 1),
} }
jt[TSTORE] = &operation{ jt[TSTORE] = &operation{
execute: opTstore, execute: OpTstore,
constantGas: params.WarmStorageReadCostEIP2929, ConstantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0), maxStack: maxStack(2, 0),
} }
} }
// opTload implements TLOAD opcode // OpTload implements TLOAD opcode
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.peek() loc := scope.Stack.peek()
hash := common.Hash(loc.Bytes32()) hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash) val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
@ -202,8 +202,8 @@ func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
return nil, nil return nil, nil
} }
// opTstore implements TSTORE opcode // OpTstore implements TSTORE opcode
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly { if interpreter.readOnly {
return nil, ErrWriteProtection return nil, ErrWriteProtection
} }
@ -225,7 +225,7 @@ func enable3855(jt *JumpTable) {
// New opcode // New opcode
jt[PUSH0] = &operation{ jt[PUSH0] = &operation{
execute: opPush0, execute: opPush0,
constantGas: GasQuickStep, ConstantGas: GasQuickStep,
minStack: minStack(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1), maxStack: maxStack(0, 1),
} }
@ -248,17 +248,17 @@ func enable3860(jt *JumpTable) {
// https://eips.ethereum.org/EIPS/eip-5656 // https://eips.ethereum.org/EIPS/eip-5656
func enable5656(jt *JumpTable) { func enable5656(jt *JumpTable) {
jt[MCOPY] = &operation{ jt[MCOPY] = &operation{
execute: opMcopy, execute: OpMcopy,
constantGas: GasFastestStep, ConstantGas: GasFastestStep,
dynamicGas: gasMcopy, dynamicGas: GasMcopy,
minStack: minStack(3, 0), minStack: minStack(3, 0),
maxStack: maxStack(3, 0), maxStack: maxStack(3, 0),
memorySize: memoryMcopy, memorySize: MemoryMcopy,
} }
} }
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656) // OpMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
var ( var (
dst = scope.Stack.pop() dst = scope.Stack.pop()
src = scope.Stack.pop() src = scope.Stack.pop()
@ -270,8 +270,8 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
return nil, nil return nil, nil
} }
// opBlobHash implements the BLOBHASH opcode // OpBlobHash implements the BLOBHASH opcode
func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
index := scope.Stack.peek() index := scope.Stack.peek()
if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) { if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) {
blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()] blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()]
@ -292,8 +292,8 @@ func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
// enable4844 applies EIP-4844 (BLOBHASH opcode) // enable4844 applies EIP-4844 (BLOBHASH opcode)
func enable4844(jt *JumpTable) { func enable4844(jt *JumpTable) {
jt[BLOBHASH] = &operation{ jt[BLOBHASH] = &operation{
execute: opBlobHash, execute: OpBlobHash,
constantGas: GasFastestStep, ConstantGas: GasFastestStep,
minStack: minStack(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1), maxStack: maxStack(1, 1),
} }
@ -303,7 +303,7 @@ func enable4844(jt *JumpTable) {
func enable7516(jt *JumpTable) { func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{ jt[BLOBBASEFEE] = &operation{
execute: opBlobBaseFee, execute: opBlobBaseFee,
constantGas: GasQuickStep, ConstantGas: GasQuickStep,
minStack: minStack(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1), maxStack: maxStack(0, 1),
} }
@ -314,7 +314,7 @@ func enable6780(jt *JumpTable) {
jt[SELFDESTRUCT] = &operation{ jt[SELFDESTRUCT] = &operation{
execute: opSelfdestruct6780, execute: opSelfdestruct6780,
dynamicGas: gasSelfdestructEIP3529, dynamicGas: gasSelfdestructEIP3529,
constantGas: params.SelfdestructGasEIP150, ConstantGas: params.SelfdestructGasEIP150,
minStack: minStack(1, 0), minStack: minStack(1, 0),
maxStack: maxStack(1, 0), maxStack: maxStack(1, 0),
} }

View file

@ -149,6 +149,10 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
return evm return evm
} }
func (evm *EVM) GetInterpreter() *EVMInterpreter {
return evm.interpreter
}
// Reset resets the EVM with a new transaction context.Reset // Reset resets the EVM with a new transaction context.Reset
// This is not threadsafe and should only be done very cautiously. // This is not threadsafe and should only be done very cautiously.
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {

View file

@ -24,9 +24,9 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
// memoryGasCost calculates the quadratic gas for memory expansion. It does so // MemoryGasCost calculates the quadratic gas for memory expansion. It does so
// only for the memory region that is expanded, not the total memory. // only for the memory region that is expanded, not the total memory.
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { func MemoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
if newMemSize == 0 { if newMemSize == 0 {
return 0, nil return 0, nil
} }
@ -38,7 +38,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
if newMemSize > 0x1FFFFFFFE0 { if newMemSize > 0x1FFFFFFFE0 {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
newMemSizeWords := toWordSize(newMemSize) newMemSizeWords := ToWordSize(newMemSize)
newMemSize = newMemSizeWords * 32 newMemSize = newMemSizeWords * 32
if newMemSize > uint64(mem.Len()) { if newMemSize > uint64(mem.Len()) {
@ -66,7 +66,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
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) {
// Gas for expanding the memory // Gas for expanding the memory
gas, err := memoryGasCost(mem, memorySize) gas, err := MemoryGasCost(mem, memorySize)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -76,7 +76,7 @@ func memoryCopierGas(stackpos int) gasFunc {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { if words, overflow = math.SafeMul(ToWordSize(words), params.CopyGas); overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
@ -90,7 +90,7 @@ func memoryCopierGas(stackpos int) gasFunc {
var ( var (
gasCallDataCopy = memoryCopierGas(2) gasCallDataCopy = memoryCopierGas(2)
gasCodeCopy = memoryCopierGas(2) gasCodeCopy = memoryCopierGas(2)
gasMcopy = memoryCopierGas(2) GasMcopy = memoryCopierGas(2)
gasExtCodeCopy = memoryCopierGas(3) gasExtCodeCopy = memoryCopierGas(3)
gasReturnDataCopy = memoryCopierGas(2) gasReturnDataCopy = memoryCopierGas(2)
) )
@ -229,7 +229,7 @@ func makeGasLog(n uint64) gasFunc {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
gas, err := memoryGasCost(mem, memorySize) gas, err := MemoryGasCost(mem, memorySize)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -253,7 +253,7 @@ func makeGasLog(n uint64) gasFunc {
} }
func gasKeccak256(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
} }
@ -261,7 +261,7 @@ func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
if overflow { if overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); 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 {
@ -274,7 +274,7 @@ func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
// static cost have a dynamic cost which is solely based on the memory // static cost have a dynamic cost which is solely based on the memory
// expansion // expansion
func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize) return MemoryGasCost(mem, memorySize)
} }
var ( var (
@ -287,7 +287,7 @@ var (
) )
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCreate2(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
} }
@ -295,7 +295,7 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
if overflow { if overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); 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 {
@ -305,7 +305,7 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
} }
func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCreateEip3860(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
} }
@ -321,7 +321,7 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
return gas, nil return gas, nil
} }
func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCreate2Eip3860(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
} }
@ -379,7 +379,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
if transfersValue { if transfersValue {
gas += params.CallValueTransferGas gas += params.CallValueTransferGas
} }
memoryGas, err := memoryGasCost(mem, memorySize) memoryGas, err := MemoryGasCost(mem, memorySize)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -399,7 +399,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
} }
func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
memoryGas, err := memoryGasCost(mem, memorySize) memoryGas, err := MemoryGasCost(mem, memorySize)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -424,7 +424,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
} }
func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasDelegateCall(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
} }
@ -440,7 +440,7 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
} }
func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasStaticCall(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
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"bytes" "bytes"
@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -41,9 +42,9 @@ func TestMemoryGasCost(t *testing.T) {
{0x1fffffffe1, 0, true}, {0x1fffffffe1, 0, true},
} }
for i, tt := range tests { for i, tt := range tests {
v, err := memoryGasCost(&Memory{}, tt.size) v, err := vm.MemoryGasCost(&vm.Memory{}, tt.size)
if (err == ErrGasUintOverflow) != tt.overflow { if (err == vm.ErrGasUintOverflow) != tt.overflow {
t.Errorf("test %d: overflow mismatch: have %v, want %v", i, err == ErrGasUintOverflow, tt.overflow) t.Errorf("test %d: overflow mismatch: have %v, want %v", i, err == vm.ErrGasUintOverflow, tt.overflow)
} }
if v != tt.cost { if v != tt.cost {
t.Errorf("test %d: gas cost mismatch: have %v, want %v", i, v, tt.cost) t.Errorf("test %d: gas cost mismatch: have %v, want %v", i, v, tt.cost)
@ -76,7 +77,7 @@ var eip2200Tests = []struct {
{1, math.MaxUint64, "0x60016000556001600055", 1612, 0, nil}, // 1 -> 1 -> 1 {1, math.MaxUint64, "0x60016000556001600055", 1612, 0, nil}, // 1 -> 1 -> 1
{0, math.MaxUint64, "0x600160005560006000556001600055", 40818, 19200, nil}, // 0 -> 1 -> 0 -> 1 {0, math.MaxUint64, "0x600160005560006000556001600055", 40818, 19200, nil}, // 0 -> 1 -> 0 -> 1
{1, math.MaxUint64, "0x600060005560016000556000600055", 10818, 19200, nil}, // 1 -> 0 -> 1 -> 0 {1, math.MaxUint64, "0x600060005560016000556000600055", 10818, 19200, nil}, // 1 -> 0 -> 1 -> 0
{1, 2306, "0x6001600055", 2306, 0, ErrOutOfGas}, // 1 -> 1 (2300 sentry + 2xPUSH) {1, 2306, "0x6001600055", 2306, 0, vm.ErrOutOfGas}, // 1 -> 1 (2300 sentry + 2xPUSH)
{1, 2307, "0x6001600055", 806, 0, nil}, // 1 -> 1 (2301 sentry + 2xPUSH) {1, 2307, "0x6001600055", 806, 0, nil}, // 1 -> 1 (2301 sentry + 2xPUSH)
} }
@ -90,13 +91,13 @@ func TestEIP2200(t *testing.T) {
statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original}))
statedb.Finalise(true) // Push the state into the "original" slot statedb.Finalise(true) // Push the state into the "original" slot
vmctx := BlockContext{ vmctx := vm.BlockContext{
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true }, CanTransfer: func(vm.StateDB, common.Address, *big.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, Transfer: func(vm.StateDB, common.Address, common.Address, *big.Int) {},
} }
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, params.AllEthashProtocolChanges, vm.Config{ExtraEips: []int{2200}})
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int)) _, gas, err := vmenv.Call(vm.AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int))
if err != tt.failure { if err != tt.failure {
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
} }
@ -140,19 +141,19 @@ func TestCreateGas(t *testing.T) {
statedb.CreateAccount(address) statedb.CreateAccount(address)
statedb.SetCode(address, hexutil.MustDecode(tt.code)) statedb.SetCode(address, hexutil.MustDecode(tt.code))
statedb.Finalise(true) statedb.Finalise(true)
vmctx := BlockContext{ vmctx := vm.BlockContext{
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true }, CanTransfer: func(vm.StateDB, common.Address, *big.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, Transfer: func(vm.StateDB, common.Address, common.Address, *big.Int) {},
BlockNumber: big.NewInt(0), BlockNumber: big.NewInt(0),
} }
config := Config{} config := vm.Config{}
if tt.eip3860 { if tt.eip3860 {
config.ExtraEips = []int{3860} config.ExtraEips = []int{3860}
} }
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config) vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, params.AllEthashProtocolChanges, config)
var startGas = uint64(testGas) var startGas = uint64(testGas)
ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(big.Int)) ret, gas, err := vmenv.Call(vm.AccountRef(common.Address{}), address, nil, startGas, new(big.Int))
if err != nil { if err != nil {
return false return false
} }

View file

@ -24,55 +24,55 @@ import (
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Add(&x, y) y.Add(&x, y)
return nil, nil return nil, nil
} }
func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Sub(&x, y) y.Sub(&x, y)
return nil, nil return nil, nil
} }
func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mul(&x, y) y.Mul(&x, y)
return nil, nil return nil, nil
} }
func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Div(&x, y) y.Div(&x, y)
return nil, nil return nil, nil
} }
func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.SDiv(&x, y) y.SDiv(&x, y)
return nil, nil return nil, nil
} }
func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mod(&x, y) y.Mod(&x, y)
return nil, nil return nil, nil
} }
func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.SMod(&x, y) y.SMod(&x, y)
return nil, nil return nil, nil
} }
func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
base, exponent := scope.Stack.pop(), scope.Stack.peek() base, exponent := scope.Stack.pop(), scope.Stack.peek()
exponent.Exp(&base, exponent) exponent.Exp(&base, exponent)
return nil, nil return nil, nil
} }
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
back, num := scope.Stack.pop(), scope.Stack.peek() back, num := scope.Stack.pop(), scope.Stack.peek()
num.ExtendSign(num, &back) num.ExtendSign(num, &back)
return nil, nil return nil, nil
@ -84,7 +84,7 @@ func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Lt(y) { if x.Lt(y) {
y.SetOne() y.SetOne()
@ -94,7 +94,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil return nil, nil
} }
func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Gt(y) { if x.Gt(y) {
y.SetOne() y.SetOne()
@ -104,7 +104,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil return nil, nil
} }
func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Slt(y) { if x.Slt(y) {
y.SetOne() y.SetOne()
@ -114,7 +114,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Sgt(y) { if x.Sgt(y) {
y.SetOne() y.SetOne()
@ -124,7 +124,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Eq(y) { if x.Eq(y) {
y.SetOne() y.SetOne()
@ -134,7 +134,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil return nil, nil
} }
func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x := scope.Stack.peek() x := scope.Stack.peek()
if x.IsZero() { if x.IsZero() {
x.SetOne() x.SetOne()
@ -144,31 +144,31 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
return nil, nil return nil, nil
} }
func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.And(&x, y) y.And(&x, y)
return nil, nil return nil, nil
} }
func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Or(&x, y) y.Or(&x, y)
return nil, nil return nil, nil
} }
func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek() x, y := scope.Stack.pop(), scope.Stack.peek()
y.Xor(&x, y) y.Xor(&x, y)
return nil, nil return nil, nil
} }
func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
th, val := scope.Stack.pop(), scope.Stack.peek() th, val := scope.Stack.pop(), scope.Stack.peek()
val.Byte(&th) val.Byte(&th)
return nil, nil return nil, nil
} }
func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
if z.IsZero() { if z.IsZero() {
z.Clear() z.Clear()
@ -178,16 +178,16 @@ func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
return nil, nil return nil, nil
} }
func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek() x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
z.MulMod(&x, &y, z) z.MulMod(&x, &y, z)
return nil, nil return nil, nil
} }
// opSHL implements Shift Left // OpSHL implements Shift Left
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the left by arg1 number of bits. // and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := scope.Stack.pop(), scope.Stack.peek() shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.LtUint64(256) { if shift.LtUint64(256) {
@ -198,10 +198,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
// opSHR implements Logical Shift Right // OpSHR implements Logical Shift Right
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := scope.Stack.pop(), scope.Stack.peek() shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.LtUint64(256) { if shift.LtUint64(256) {
@ -212,10 +212,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
// opSAR implements Arithmetic Shift Right // OpSAR implements Arithmetic Shift Right
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
shift, value := scope.Stack.pop(), scope.Stack.peek() shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.GtUint64(256) { if shift.GtUint64(256) {
if value.Sign() >= 0 { if value.Sign() >= 0 {
@ -231,7 +231,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.peek() offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
@ -252,7 +252,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
return nil, nil return nil, nil
} }
func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes())) scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
return nil, nil return nil, nil
} }
@ -264,7 +264,7 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
return nil, nil return nil, nil
} }
func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes())) scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil return nil, nil
} }
@ -476,7 +476,7 @@ func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
return nil, nil return nil, nil
} }
func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes()) v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes())
scope.Stack.push(v) scope.Stack.push(v)
return nil, nil return nil, nil
@ -499,14 +499,14 @@ func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
return nil, nil return nil, nil
} }
func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// pop value of the stack // pop value of the stack
mStart, val := scope.Stack.pop(), scope.Stack.pop() mStart, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.Set32(mStart.Uint64(), &val) scope.Memory.Set32(mStart.Uint64(), &val)
return nil, nil return nil, nil
} }
func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func OpMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
off, val := scope.Stack.pop(), scope.Stack.pop() off, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.store[off.Uint64()] = byte(val.Uint64()) scope.Memory.store[off.Uint64()] = byte(val.Uint64())
return nil, nil return nil, nil
@ -850,7 +850,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
// following functions are used by the instruction jump table // following functions are used by the instruction jump table
// make log instruction function // make log instruction function
func makeLog(size int) executionFunc { func makeLog(size int) ExecutionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly { if interpreter.readOnly {
return nil, ErrWriteProtection return nil, ErrWriteProtection
@ -893,7 +893,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
} }
// make push instruction function // make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc { func makePush(size uint64, pushByteSize int) ExecutionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
codeLen := len(scope.Contract.Code) codeLen := len(scope.Contract.Code)
@ -917,7 +917,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
} }
// make dup instruction function // make dup instruction function
func makeDup(size int64) executionFunc { func makeDup(size int64) ExecutionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.dup(int(size)) scope.Stack.dup(int(size))
return nil, nil return nil, nil
@ -925,7 +925,7 @@ func makeDup(size int64) executionFunc {
} }
// make swap instruction function // make swap instruction function
func makeSwap(size int64) executionFunc { func makeSwap(size int64) ExecutionFunc {
// switch n + 1 otherwise n would be swapped with n // switch n + 1 otherwise n would be swapped with n
size++ size++
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"bytes" "bytes"
@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256" "github.com/holiman/uint256"
@ -48,7 +49,7 @@ type twoOperandParams struct {
var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
var commonParams []*twoOperandParams var commonParams []*twoOperandParams
var twoOpMethods map[string]executionFunc var twoOpMethods map[string]vm.ExecutionFunc
type contractRef struct { type contractRef struct {
addr common.Address addr common.Address
@ -78,50 +79,50 @@ func init() {
commonParams[i*len(params)+j] = &twoOperandParams{x, y} commonParams[i*len(params)+j] = &twoOperandParams{x, y}
} }
} }
twoOpMethods = map[string]executionFunc{ twoOpMethods = map[string]vm.ExecutionFunc{
"add": opAdd, "add": vm.OpAdd,
"sub": opSub, "sub": vm.OpSub,
"mul": opMul, "mul": vm.OpMul,
"div": opDiv, "div": vm.OpDiv,
"sdiv": opSdiv, "sdiv": vm.OpSdiv,
"mod": opMod, "mod": vm.OpMod,
"smod": opSmod, "smod": vm.OpSmod,
"exp": opExp, "exp": vm.OpExp,
"signext": opSignExtend, "signext": vm.OpSignExtend,
"lt": opLt, "lt": vm.OpLt,
"gt": opGt, "gt": vm.OpGt,
"slt": opSlt, "slt": vm.OpSlt,
"sgt": opSgt, "sgt": vm.OpSgt,
"eq": opEq, "eq": vm.OpEq,
"and": opAnd, "and": vm.OpAnd,
"or": opOr, "or": vm.OpOr,
"xor": opXor, "xor": vm.OpXor,
"byte": opByte, "byte": vm.OpByte,
"shl": opSHL, "shl": vm.OpSHL,
"shr": opSHR, "shr": vm.OpSHR,
"sar": opSAR, "sar": vm.OpSAR,
} }
} }
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) { func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn vm.ExecutionFunc, name string) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
pc = uint64(0) pc = uint64(0)
evmInterpreter = env.interpreter evmInterpreter = env.GetInterpreter()
) )
for i, test := range tests { for i, test := range tests {
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X)) x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X))
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y)) y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y))
expected := new(uint256.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, &ScopeContext{nil, stack, nil}) opFn(&pc, evmInterpreter, &vm.ScopeContext{nil, stack, nil})
if len(stack.data) != 1 { if len(stack.Data()) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data)) 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)
@ -140,7 +141,7 @@ func TestByteOp(t *testing.T) {
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "20", "00"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "20", "00"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "FFFFFFFFFFFFFFFF", "00"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "FFFFFFFFFFFFFFFF", "00"},
} }
testTwoOperandOp(t, tests, opByte, "byte") testTwoOperandOp(t, tests, vm.OpByte, "byte")
} }
func TestSHL(t *testing.T) { func TestSHL(t *testing.T) {
@ -157,7 +158,7 @@ func TestSHL(t *testing.T) {
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, {"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"}, {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
} }
testTwoOperandOp(t, tests, opSHL, "shl") testTwoOperandOp(t, tests, vm.OpSHL, "shl")
} }
func TestSHR(t *testing.T) { func TestSHR(t *testing.T) {
@ -175,7 +176,7 @@ func TestSHR(t *testing.T) {
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, {"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
} }
testTwoOperandOp(t, tests, opSHR, "shr") testTwoOperandOp(t, tests, vm.OpSHR, "shr")
} }
func TestSAR(t *testing.T) { func TestSAR(t *testing.T) {
@ -199,14 +200,14 @@ func TestSAR(t *testing.T) {
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
} }
testTwoOperandOp(t, tests, opSAR, "sar") testTwoOperandOp(t, tests, vm.OpSAR, "sar")
} }
func TestAddMod(t *testing.T) { func TestAddMod(t *testing.T) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
pc = uint64(0) pc = uint64(0)
) )
tests := []struct { tests := []struct {
@ -229,11 +230,11 @@ func TestAddMod(t *testing.T) {
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.y)) y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.y))
z := new(uint256.Int).SetBytes(common.Hex2Bytes(test.z)) z := new(uint256.Int).SetBytes(common.Hex2Bytes(test.z))
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.expected)) expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.expected))
stack.push(z) stack.Push(z)
stack.push(y) stack.Push(y)
stack.push(x) stack.Push(x)
opAddmod(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) vm.OpAddmod(&pc, evmInterpreter, &vm.ScopeContext{nil, stack, nil})
actual := stack.pop() actual := stack.Pop()
if actual.Cmp(expected) != 0 { if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual) t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
} }
@ -246,21 +247,21 @@ func TestWriteExpectedValues(t *testing.T) {
t.Skip("Enable this test to create json test cases.") t.Skip("Enable this test to create json test cases.")
// getResult is a convenience function to generate the expected values // getResult is a convenience function to generate the expected values
getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { getResult := func(args []*twoOperandParams, opFn vm.ExecutionFunc) []TwoOperandTestcase {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
pc = uint64(0) pc = uint64(0)
interpreter = env.interpreter interpreter = env.Interpreter()
) )
result := make([]TwoOperandTestcase, len(args)) result := make([]TwoOperandTestcase, len(args))
for i, param := range args { for i, param := range args {
x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x)) x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x))
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
stack.push(x) stack.Push(x)
stack.push(y) stack.Push(y)
opFn(&pc, interpreter, &ScopeContext{nil, stack, nil}) opFn(&pc, interpreter, &vm.ScopeContext{nil, stack, nil})
actual := stack.pop() actual := stack.Pop()
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
} }
return result return result
@ -291,15 +292,15 @@ func TestJsonTestcases(t *testing.T) {
} }
} }
func opBenchmark(bench *testing.B, op executionFunc, args ...string) { func opBenchmark(bench *testing.B, op vm.ExecutionFunc, args ...string) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
scope = &ScopeContext{nil, stack, nil} scope = &vm.ScopeContext{nil, stack, nil}
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
) )
env.interpreter = evmInterpreter env.SetInterpreter(evmInterpreter)
// convert args // convert args
intArgs := make([]*uint256.Int, len(args)) intArgs := make([]*uint256.Int, len(args))
for i, arg := range args { for i, arg := range args {
@ -309,10 +310,10 @@ 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 intArgs { for _, arg := range intArgs {
stack.push(arg) stack.Push(arg)
} }
op(&pc, evmInterpreter, scope) op(&pc, evmInterpreter, scope)
stack.pop() stack.Pop()
} }
bench.StopTimer() bench.StopTimer()
@ -328,169 +329,169 @@ func BenchmarkOpAdd64(b *testing.B) {
x := "ffffffff" x := "ffffffff"
y := "fd37f3e2bba2c4f" y := "fd37f3e2bba2c4f"
opBenchmark(b, opAdd, x, y) opBenchmark(b, vm.OpAdd, x, y)
} }
func BenchmarkOpAdd128(b *testing.B) { func BenchmarkOpAdd128(b *testing.B) {
x := "ffffffffffffffff" x := "ffffffffffffffff"
y := "f5470b43c6549b016288e9a65629687" y := "f5470b43c6549b016288e9a65629687"
opBenchmark(b, opAdd, x, y) opBenchmark(b, vm.OpAdd, x, y)
} }
func BenchmarkOpAdd256(b *testing.B) { func BenchmarkOpAdd256(b *testing.B) {
x := "0802431afcbce1fc194c9eaa417b2fb67dc75a95db0bc7ec6b1c8af11df6a1da9" x := "0802431afcbce1fc194c9eaa417b2fb67dc75a95db0bc7ec6b1c8af11df6a1da9"
y := "a1f5aac137876480252e5dcac62c354ec0d42b76b0642b6181ed099849ea1d57" y := "a1f5aac137876480252e5dcac62c354ec0d42b76b0642b6181ed099849ea1d57"
opBenchmark(b, opAdd, x, y) opBenchmark(b, vm.OpAdd, x, y)
} }
func BenchmarkOpSub64(b *testing.B) { func BenchmarkOpSub64(b *testing.B) {
x := "51022b6317003a9d" x := "51022b6317003a9d"
y := "a20456c62e00753a" y := "a20456c62e00753a"
opBenchmark(b, opSub, x, y) opBenchmark(b, vm.OpSub, x, y)
} }
func BenchmarkOpSub128(b *testing.B) { func BenchmarkOpSub128(b *testing.B) {
x := "4dde30faaacdc14d00327aac314e915d" x := "4dde30faaacdc14d00327aac314e915d"
y := "9bbc61f5559b829a0064f558629d22ba" y := "9bbc61f5559b829a0064f558629d22ba"
opBenchmark(b, opSub, x, y) opBenchmark(b, vm.OpSub, x, y)
} }
func BenchmarkOpSub256(b *testing.B) { func BenchmarkOpSub256(b *testing.B) {
x := "4bfcd8bb2ac462735b48a17580690283980aa2d679f091c64364594df113ea37" x := "4bfcd8bb2ac462735b48a17580690283980aa2d679f091c64364594df113ea37"
y := "97f9b1765588c4e6b69142eb00d20507301545acf3e1238c86c8b29be227d46e" y := "97f9b1765588c4e6b69142eb00d20507301545acf3e1238c86c8b29be227d46e"
opBenchmark(b, opSub, x, y) opBenchmark(b, vm.OpSub, x, y)
} }
func BenchmarkOpMul(b *testing.B) { func BenchmarkOpMul(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opMul, x, y) opBenchmark(b, vm.OpMul, x, y)
} }
func BenchmarkOpDiv256(b *testing.B) { func BenchmarkOpDiv256(b *testing.B) {
x := "ff3f9014f20db29ae04af2c2d265de17" x := "ff3f9014f20db29ae04af2c2d265de17"
y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611" y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611"
opBenchmark(b, opDiv, x, y) opBenchmark(b, vm.OpDiv, x, y)
} }
func BenchmarkOpDiv128(b *testing.B) { func BenchmarkOpDiv128(b *testing.B) {
x := "fdedc7f10142ff97" x := "fdedc7f10142ff97"
y := "fbdfda0e2ce356173d1993d5f70a2b11" y := "fbdfda0e2ce356173d1993d5f70a2b11"
opBenchmark(b, opDiv, x, y) opBenchmark(b, vm.OpDiv, x, y)
} }
func BenchmarkOpDiv64(b *testing.B) { func BenchmarkOpDiv64(b *testing.B) {
x := "fcb34eb3" x := "fcb34eb3"
y := "f97180878e839129" y := "f97180878e839129"
opBenchmark(b, opDiv, x, y) opBenchmark(b, vm.OpDiv, x, y)
} }
func BenchmarkOpSdiv(b *testing.B) { func BenchmarkOpSdiv(b *testing.B) {
x := "ff3f9014f20db29ae04af2c2d265de17" x := "ff3f9014f20db29ae04af2c2d265de17"
y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611" y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611"
opBenchmark(b, opSdiv, x, y) opBenchmark(b, vm.OpSdiv, x, y)
} }
func BenchmarkOpMod(b *testing.B) { func BenchmarkOpMod(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opMod, x, y) opBenchmark(b, vm.OpMod, x, y)
} }
func BenchmarkOpSmod(b *testing.B) { func BenchmarkOpSmod(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opSmod, x, y) opBenchmark(b, vm.OpSmod, x, y)
} }
func BenchmarkOpExp(b *testing.B) { func BenchmarkOpExp(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opExp, x, y) opBenchmark(b, vm.OpExp, x, y)
} }
func BenchmarkOpSignExtend(b *testing.B) { func BenchmarkOpSignExtend(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opSignExtend, x, y) opBenchmark(b, vm.OpSignExtend, x, y)
} }
func BenchmarkOpLt(b *testing.B) { func BenchmarkOpLt(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opLt, x, y) opBenchmark(b, vm.OpLt, x, y)
} }
func BenchmarkOpGt(b *testing.B) { func BenchmarkOpGt(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opGt, x, y) opBenchmark(b, vm.OpGt, x, y)
} }
func BenchmarkOpSlt(b *testing.B) { func BenchmarkOpSlt(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opSlt, x, y) opBenchmark(b, vm.OpSlt, x, y)
} }
func BenchmarkOpSgt(b *testing.B) { func BenchmarkOpSgt(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opSgt, x, y) opBenchmark(b, vm.OpSgt, x, y)
} }
func BenchmarkOpEq(b *testing.B) { func BenchmarkOpEq(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opEq, x, y) opBenchmark(b, vm.OpEq, x, y)
} }
func BenchmarkOpEq2(b *testing.B) { func BenchmarkOpEq2(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe" y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
opBenchmark(b, opEq, x, y) opBenchmark(b, vm.OpEq, x, y)
} }
func BenchmarkOpAnd(b *testing.B) { func BenchmarkOpAnd(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opAnd, x, y) opBenchmark(b, vm.OpAnd, x, y)
} }
func BenchmarkOpOr(b *testing.B) { func BenchmarkOpOr(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opOr, x, y) opBenchmark(b, vm.OpOr, x, y)
} }
func BenchmarkOpXor(b *testing.B) { func BenchmarkOpXor(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opXor, x, y) opBenchmark(b, vm.OpXor, x, y)
} }
func BenchmarkOpByte(b *testing.B) { func BenchmarkOpByte(b *testing.B) {
x := alphabetSoup x := alphabetSoup
y := alphabetSoup y := alphabetSoup
opBenchmark(b, opByte, x, y) opBenchmark(b, vm.OpByte, x, y)
} }
func BenchmarkOpAddmod(b *testing.B) { func BenchmarkOpAddmod(b *testing.B) {
@ -498,7 +499,7 @@ func BenchmarkOpAddmod(b *testing.B) {
y := alphabetSoup y := alphabetSoup
z := alphabetSoup z := alphabetSoup
opBenchmark(b, opAddmod, x, y, z) opBenchmark(b, vm.OpAddmod, x, y, z)
} }
func BenchmarkOpMulmod(b *testing.B) { func BenchmarkOpMulmod(b *testing.B) {
@ -506,53 +507,53 @@ func BenchmarkOpMulmod(b *testing.B) {
y := alphabetSoup y := alphabetSoup
z := alphabetSoup z := alphabetSoup
opBenchmark(b, opMulmod, x, y, z) opBenchmark(b, vm.OpMulmod, x, y, z)
} }
func BenchmarkOpSHL(b *testing.B) { func BenchmarkOpSHL(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff" y := "ff"
opBenchmark(b, opSHL, x, y) opBenchmark(b, vm.OpSHL, x, y)
} }
func BenchmarkOpSHR(b *testing.B) { func BenchmarkOpSHR(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff" y := "ff"
opBenchmark(b, opSHR, x, y) opBenchmark(b, vm.OpSHR, x, y)
} }
func BenchmarkOpSAR(b *testing.B) { func BenchmarkOpSAR(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff" y := "ff"
opBenchmark(b, opSAR, x, y) opBenchmark(b, vm.OpSAR, x, y)
} }
func BenchmarkOpIsZero(b *testing.B) { func BenchmarkOpIsZero(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
opBenchmark(b, opIszero, x) opBenchmark(b, vm.OpIszero, x)
} }
func TestOpMstore(t *testing.T) { func TestOpMstore(t *testing.T) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
mem = NewMemory() mem = vm.NewMemory()
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
) )
env.interpreter = evmInterpreter env.SetInterpreter(evmInterpreter)
mem.Resize(64) mem.Resize(64)
pc := uint64(0) pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v))) stack.Push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
stack.push(new(uint256.Int)) stack.Push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) vm.OpMstore(&pc, evmInterpreter, &vm.ScopeContext{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.push(new(uint256.Int).SetUint64(0x1)) stack.Push(new(uint256.Int).SetUint64(0x1))
stack.push(new(uint256.Int)) stack.Push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) vm.OpMstore(&pc, evmInterpreter, &vm.ScopeContext{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")
} }
@ -560,13 +561,13 @@ func TestOpMstore(t *testing.T) {
func BenchmarkOpMstore(bench *testing.B) { func BenchmarkOpMstore(bench *testing.B) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
mem = NewMemory() mem = vm.NewMemory()
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
) )
env.interpreter = evmInterpreter env.SetInterpreter(evmInterpreter)
mem.Resize(64) mem.Resize(64)
pc := uint64(0) pc := uint64(0)
memStart := new(uint256.Int) memStart := new(uint256.Int)
@ -574,24 +575,24 @@ func BenchmarkOpMstore(bench *testing.B) {
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
stack.push(value) stack.Push(value)
stack.push(memStart) stack.Push(memStart)
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) vm.OpMstore(&pc, evmInterpreter, &vm.ScopeContext{mem, stack, nil})
} }
} }
func TestOpTstore(t *testing.T) { func TestOpTstore(t *testing.T) {
var ( var (
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, statedb, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
mem = NewMemory() mem = vm.NewMemory()
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
caller = common.Address{} caller = common.Address{}
to = common.Address{1} to = common.Address{1}
contractRef = contractRef{caller} contractRef = contractRef{caller}
contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0) contract = vm.NewContract(contractRef, vm.AccountRef(to), new(big.Int), 0)
scopeContext = ScopeContext{mem, stack, contract} scopeContext = vm.ScopeContext{mem, stack, contract}
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
) )
@ -599,25 +600,25 @@ func TestOpTstore(t *testing.T) {
statedb.CreateAccount(caller) statedb.CreateAccount(caller)
statedb.CreateAccount(to) statedb.CreateAccount(to)
env.interpreter = evmInterpreter env.SetInterpreter(evmInterpreter)
pc := uint64(0) pc := uint64(0)
// push the value to the stack // push the value to the stack
stack.push(new(uint256.Int).SetBytes(value)) stack.Push(new(uint256.Int).SetBytes(value))
// push the location to the stack // push the location to the stack
stack.push(new(uint256.Int)) stack.Push(new(uint256.Int))
opTstore(&pc, evmInterpreter, &scopeContext) vm.OpTstore(&pc, evmInterpreter, &scopeContext)
// there should be no elements on the stack after TSTORE // there should be no elements on the stack after TSTORE
if stack.len() != 0 { if stack.Len() != 0 {
t.Fatal("stack wrong size") t.Fatal("stack wrong size")
} }
// push the location to the stack // push the location to the stack
stack.push(new(uint256.Int)) stack.Push(new(uint256.Int))
opTload(&pc, evmInterpreter, &scopeContext) vm.OpTload(&pc, evmInterpreter, &scopeContext)
// there should be one element on the stack after TLOAD // there should be one element on the stack after TLOAD
if stack.len() != 1 { if stack.Len() != 1 {
t.Fatal("stack wrong size") t.Fatal("stack wrong size")
} }
val := stack.peek() val := stack.Peek()
if !bytes.Equal(val.Bytes(), value) { if !bytes.Equal(val.Bytes(), value) {
t.Fatal("incorrect element read from transient storage") t.Fatal("incorrect element read from transient storage")
} }
@ -625,21 +626,21 @@ func TestOpTstore(t *testing.T) {
func BenchmarkOpKeccak256(bench *testing.B) { func BenchmarkOpKeccak256(bench *testing.B) {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
mem = NewMemory() mem = vm.NewMemory()
evmInterpreter = NewEVMInterpreter(env) evmInterpreter = vm.NewEVMInterpreter(env)
) )
env.interpreter = evmInterpreter env.SetInterpreter(evmInterpreter)
mem.Resize(32) mem.Resize(32)
pc := uint64(0) pc := uint64(0)
start := new(uint256.Int) start := new(uint256.Int)
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
stack.push(uint256.NewInt(32)) stack.Push(uint256.NewInt(32))
stack.push(start) stack.Push(start)
opKeccak256(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) vm.OpKeccak256(&pc, evmInterpreter, &vm.ScopeContext{mem, stack, nil})
} }
} }
@ -701,11 +702,11 @@ func TestCreate2Addreses(t *testing.T) {
codeHash := crypto.Keccak256(code) codeHash := crypto.Keccak256(code)
address := crypto.CreateAddress2(origin, salt, codeHash) address := crypto.CreateAddress2(origin, salt, codeHash)
/* /*
stack := newstack() stack :=vm.Newstack()
// salt, but we don't need that for this test // salt, but we don't need that for this test
stack.push(big.NewInt(int64(len(code)))) //size stack.Push(big.NewInt(int64(len(code)))) //size
stack.push(big.NewInt(0)) // memstart stack.Push(big.NewInt(0)) // memstart
stack.push(big.NewInt(0)) // value stack.Push(big.NewInt(0)) // value
gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0) gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0)
fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String()) fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String())
*/ */
@ -729,16 +730,16 @@ func TestRandom(t *testing.T) {
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})}, {name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
} { } {
var ( var (
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{Random: &tt.random}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
pc = uint64(0) pc = uint64(0)
evmInterpreter = env.interpreter evmInterpreter = env.Interpreter()
) )
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) vm.OpRandom(&pc, evmInterpreter, &vm.ScopeContext{nil, stack, nil})
if len(stack.data) != 1 { if len(stack.Data()) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.Data()))
} }
actual := stack.pop() actual := stack.Pop()
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes())) expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes()))
if overflow { if overflow {
t.Errorf("Testcase %v: invalid overflow", tt.name) t.Errorf("Testcase %v: invalid overflow", tt.name)
@ -770,17 +771,17 @@ func TestBlobHash(t *testing.T) {
{name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil}, {name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil},
} { } {
var ( var (
env = NewEVM(BlockContext{}, TxContext{BlobHashes: tt.hashes}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{BlobHashes: tt.hashes}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
pc = uint64(0) pc = uint64(0)
evmInterpreter = env.interpreter evmInterpreter = env.Interpreter()
) )
stack.push(uint256.NewInt(tt.idx)) stack.Push(uint256.NewInt(tt.idx))
opBlobHash(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) vm.OpBlobHash(&pc, evmInterpreter, &vm.ScopeContext{nil, stack, nil})
if len(stack.data) != 1 { if len(stack.Data()) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.Data()))
} }
actual := stack.pop() actual := stack.Pop()
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.expect.Bytes())) expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.expect.Bytes()))
if overflow { if overflow {
t.Errorf("Testcase %v: invalid overflow", tt.name) t.Errorf("Testcase %v: invalid overflow", tt.name)
@ -873,14 +874,14 @@ func TestOpMCopy(t *testing.T) {
}, },
} { } {
var ( var (
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, nil, params.TestChainConfig, vm.Config{})
stack = newstack() stack = vm.Newstack()
pc = uint64(0) pc = uint64(0)
evmInterpreter = env.interpreter evmInterpreter = env.Interpreter()
) )
data := common.FromHex(strings.ReplaceAll(tc.pre, " ", "")) data := common.FromHex(strings.ReplaceAll(tc.pre, " ", ""))
// Set pre // Set pre
mem := NewMemory() mem := vm.NewMemory()
mem.Resize(uint64(len(data))) mem.Resize(uint64(len(data)))
mem.Set(0, uint64(len(data)), data) mem.Set(0, uint64(len(data)), data)
// Push stack args // Push stack args
@ -888,38 +889,38 @@ func TestOpMCopy(t *testing.T) {
src, _ := uint256.FromHex(tc.src) src, _ := uint256.FromHex(tc.src)
dst, _ := uint256.FromHex(tc.dst) dst, _ := uint256.FromHex(tc.dst)
stack.push(len) stack.Push(len)
stack.push(src) stack.Push(src)
stack.push(dst) stack.Push(dst)
wantErr := (tc.wantGas == 0) wantErr := (tc.wantGas == 0)
// Calc mem expansion // Calc mem expansion
var memorySize uint64 var memorySize uint64
if memSize, overflow := memoryMcopy(stack); overflow { if memSize, overflow := vm.MemoryMcopy(stack); overflow {
if wantErr { if wantErr {
continue continue
} }
t.Errorf("overflow") t.Errorf("overflow")
} else { } else {
var overflow bool var overflow bool
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { if memorySize, overflow = math.SafeMul(vm.ToWordSize(memSize), 32); overflow {
t.Error(ErrGasUintOverflow) t.Error(vm.ErrGasUintOverflow)
} }
} }
// and the dynamic cost // and the dynamic cost
var haveGas uint64 var haveGas uint64
if dynamicCost, err := gasMcopy(env, nil, stack, mem, memorySize); err != nil { if dynamicCost, err := vm.GasMcopy(env, nil, stack, mem, memorySize); err != nil {
t.Error(err) t.Error(err)
} else { } else {
haveGas = GasFastestStep + dynamicCost haveGas = vm.GasFastestStep + dynamicCost
} }
// Expand mem // Expand mem
if memorySize > 0 { if memorySize > 0 {
mem.Resize(memorySize) mem.Resize(memorySize)
} }
// Do the copy // Do the copy
opMcopy(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) vm.OpMcopy(&pc, evmInterpreter, &vm.ScopeContext{mem, stack, nil})
want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
if have := mem.store; !bytes.Equal(want, have) { if have := mem.GetStore(); !bytes.Equal(want, have) {
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have) t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)
} }
wantGas := tc.wantGas wantGas := tc.wantGas

View file

@ -20,7 +20,6 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -88,7 +87,7 @@ type StateDB interface {
Finalise(deleteEmptyObjects bool) Finalise(deleteEmptyObjects bool)
Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error)
SetTxContext(thash common.Hash, ti int) SetTxContext(thash common.Hash, ti int)
Copy() *state.StateDB Copy() StateDB
IntermediateRoot(deleteEmptyObjects bool) common.Hash IntermediateRoot(deleteEmptyObjects bool) common.Hash
GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log
TxIndex() int TxIndex() int

View file

@ -84,7 +84,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
var extraEips []int var extraEips []int
if len(evm.Config.ExtraEips) > 0 { if len(evm.Config.ExtraEips) > 0 {
// Deep-copy jumptable to prevent modification of opcodes in other tables // Deep-copy jumptable to prevent modification of opcodes in other tables
table = copyJumpTable(table) table = CopyJumpTable(table)
} }
for _, eip := range evm.Config.ExtraEips { for _, eip := range evm.Config.ExtraEips {
if err := EnableEIP(eip, table); err != nil { if err := EnableEIP(eip, table); err != nil {
@ -128,7 +128,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
var ( var (
op OpCode // current opcode op OpCode // current opcode
mem = NewMemory() // bound memory mem = NewMemory() // bound memory
stack = newstack() // local stack stack = Newstack() // local stack
callContext = &ScopeContext{ callContext = &ScopeContext{
Memory: mem, Memory: mem,
Stack: stack, Stack: stack,
@ -178,7 +178,7 @@ 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.table[op] operation := in.table[op]
cost = operation.constantGas // For tracing cost = operation.ConstantGas // For tracing
// 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}
@ -202,7 +202,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} }
// memory is expanded in words of 32 bytes. Gas // memory is expanded in words of 32 bytes. Gas
// is also calculated in words. // is also calculated in words.
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { if memorySize, overflow = math.SafeMul(ToWordSize(memSize), 32); overflow {
return nil, ErrGasUintOverflow return nil, ErrGasUintOverflow
} }
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"math/big" "math/big"
@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -38,8 +39,8 @@ var loopInterruptTests = []string{
func TestLoopInterrupt(t *testing.T) { func TestLoopInterrupt(t *testing.T) {
address := common.BytesToAddress([]byte("contract")) address := common.BytesToAddress([]byte("contract"))
vmctx := BlockContext{ vmctx := vm.BlockContext{
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, Transfer: func(vm.StateDB, common.Address, common.Address, *big.Int) {},
} }
for i, tt := range loopInterruptTests { for i, tt := range loopInterruptTests {
@ -48,13 +49,13 @@ func TestLoopInterrupt(t *testing.T) {
statedb.SetCode(address, common.Hex2Bytes(tt)) statedb.SetCode(address, common.Hex2Bytes(tt))
statedb.Finalise(true) statedb.Finalise(true)
evm := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{}) evm := vm.NewEVM(vmctx, vm.TxContext{}, statedb, params.AllEthashProtocolChanges, vm.Config{})
errChannel := make(chan error) errChannel := make(chan error)
timeout := make(chan bool) timeout := make(chan bool)
go func(evm *EVM) { go func(evm *vm.EVM) {
_, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(big.Int)) _, _, err := evm.Call(vm.AccountRef(common.Address{}), address, nil, math.MaxUint64, new(big.Int))
errChannel <- err errChannel <- err
}(evm) }(evm)

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,7 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
case rules.IsShanghai: case rules.IsShanghai:
return newShanghaiInstructionSet(), nil return newShanghaiInstructionSet(), nil
case rules.IsMerge: case rules.IsMerge:
return newMergeInstructionSet(), nil return NewMergeInstructionSet(), nil
case rules.IsLondon: case rules.IsLondon:
return newLondonInstructionSet(), nil return newLondonInstructionSet(), nil
case rules.IsBerlin: case rules.IsBerlin:
@ -72,5 +72,5 @@ func (op *operation) HasCost() bool {
// However, go-lang does now allow that. So we'll just check some other // However, go-lang does now allow that. So we'll just check some other
// 'indicators' that this is an invalid op. Alas, STOP is impossible to // 'indicators' that this is an invalid op. Alas, STOP is impossible to
// filter out // filter out
return op.dynamicGas != nil || op.constantGas != 0 return op.dynamicGas != nil || op.ConstantGas != 0
} }

View file

@ -14,22 +14,23 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm_test
import ( import (
"testing" "testing"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// TestJumpTableCopy tests that deep copy is necessery to prevent modify shared jump table // TestJumpTableCopy tests that deep copy is necessery to prevent modify shared jump table
func TestJumpTableCopy(t *testing.T) { func TestJumpTableCopy(t *testing.T) {
tbl := newMergeInstructionSet() tbl := vm.NewMergeInstructionSet()
require.Equal(t, uint64(0), tbl[SLOAD].constantGas) require.Equal(t, uint64(0), tbl[vm.SLOAD].ConstantGas)
// a deep copy won't modify the shared jump table // a deep copy won't modify the shared jump table
deepCopy := copyJumpTable(&tbl) deepCopy := vm.CopyJumpTable(&tbl)
deepCopy[SLOAD].constantGas = 100 deepCopy[vm.SLOAD].ConstantGas = 100
require.Equal(t, uint64(100), deepCopy[SLOAD].constantGas) require.Equal(t, uint64(100), deepCopy[vm.SLOAD].ConstantGas)
require.Equal(t, uint64(0), tbl[SLOAD].constantGas) require.Equal(t, uint64(0), tbl[vm.SLOAD].ConstantGas)
} }

View file

@ -114,3 +114,7 @@ func (m *Memory) Copy(dst, src, len uint64) {
} }
copy(m.store[dst:], m.store[src:src+len]) copy(m.store[dst:], m.store[src:src+len])
} }
func (m *Memory) GetStore() []byte {
return m.store
}

View file

@ -48,7 +48,7 @@ func memoryMStore(stack *Stack) (uint64, bool) {
return calcMemSize64WithUint(stack.Back(0), 32) return calcMemSize64WithUint(stack.Back(0), 32)
} }
func memoryMcopy(stack *Stack) (uint64, bool) { func MemoryMcopy(stack *Stack) (uint64, bool) {
mStart := stack.Back(0) // stack[0]: dest mStart := stack.Back(0) // stack[0]: dest
if stack.Back(1).Gt(mStart) { if stack.Back(1).Gt(mStart) {
mStart = stack.Back(1) // stack[1]: source mStart = stack.Back(1) // stack[1]: source

View file

@ -1,4 +1,4 @@
package vm package vm_test
import ( import (
"bytes" "bytes"
@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
) )
func TestMemoryCopy(t *testing.T) { func TestMemoryCopy(t *testing.T) {
@ -53,7 +54,7 @@ func TestMemoryCopy(t *testing.T) {
"11", "11",
}, },
} { } {
m := NewMemory() m := vm.NewMemory()
// Clean spaces // Clean spaces
data := common.FromHex(strings.ReplaceAll(tc.pre, " ", "")) data := common.FromHex(strings.ReplaceAll(tc.pre, " ", ""))
// Set pre // Set pre
@ -62,7 +63,7 @@ func TestMemoryCopy(t *testing.T) {
// Do the copy // Do the copy
m.Copy(tc.dst, tc.src, tc.len) m.Copy(tc.dst, tc.src, tc.len)
want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
if have := m.store; !bytes.Equal(want, have) { if have := m.GetStore(); !bytes.Equal(want, have) {
t.Errorf("case %d: want: %#x\nhave: %#x\n", i, want, have) t.Errorf("case %d: want: %#x\nhave: %#x\n", i, want, have)
} }
} }

View file

@ -129,7 +129,7 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo
if !evm.StateDB.AddressInAccessList(addr) { if !evm.StateDB.AddressInAccessList(addr) {
evm.StateDB.AddAddressToAccessList(addr) evm.StateDB.AddAddressToAccessList(addr)
var overflow bool var overflow bool
// We charge (cold-warm), since 'warm' is already charged as constantGas // We charge (cold-warm), since 'warm' is already charged as ConstantGas
if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow { if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
@ -151,7 +151,7 @@ func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Mem
if !evm.StateDB.AddressInAccessList(addr) { if !evm.StateDB.AddressInAccessList(addr) {
// If the caller cannot afford the cost, this change will be rolled back // If the caller cannot afford the cost, this change will be rolled back
evm.StateDB.AddAddressToAccessList(addr) evm.StateDB.AddAddressToAccessList(addr)
// The warm storage read cost is already charged as constantGas // The warm storage read cost is already charged as ConstantGas
return params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929, nil return params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929, nil
} }
return 0, nil return 0, nil

View file

@ -35,7 +35,7 @@ type Stack struct {
data []uint256.Int data []uint256.Int
} }
func newstack() *Stack { func Newstack() *Stack {
return stackPool.Get().(*Stack) return stackPool.Get().(*Stack)
} }
@ -80,3 +80,27 @@ func (st *Stack) peek() *uint256.Int {
func (st *Stack) Back(n int) *uint256.Int { func (st *Stack) Back(n int) *uint256.Int {
return &st.data[st.len()-n-1] return &st.data[st.len()-n-1]
} }
func (st *Stack) Push(d *uint256.Int) {
st.push(d)
}
func (st *Stack) Pop() (ret uint256.Int) {
return st.pop()
}
func (st *Stack) Len() int {
return st.len()
}
func (st *Stack) Swap(n int) {
st.swap(n)
}
func (st *Stack) Dup(n int) {
st.dup(n)
}
func (st *Stack) Peek() *uint256.Int {
return st.peek()
}

View file

@ -184,7 +184,7 @@ type txTraceResult struct {
// blockTraceTask represents a single block trace task when an entire chain is // blockTraceTask represents a single block trace task when an entire chain is
// being traced. // being traced.
type blockTraceTask struct { type blockTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing statedb vm.StateDB // Intermediate state prepped for tracing
block *types.Block // Block to trace the transactions from block *types.Block // Block to trace the transactions from
release StateReleaseFunc // The function to release the held resource for this task release StateReleaseFunc // The function to release the held resource for this task
results []*txTraceResult // Trace results produced by the task results []*txTraceResult // Trace results produced by the task
@ -201,8 +201,8 @@ type blockTraceResult struct {
// txTraceTask represents a single transaction trace task when an entire block // txTraceTask represents a single transaction trace task when an entire block
// is being traced. // is being traced.
type txTraceTask struct { type txTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing statedb vm.StateDB // Intermediate state prepped for tracing
index int // Transaction offset in the block index int // Transaction offset in the block
} }
// TraceChain returns the structured logs created during the execution of EVM // TraceChain returns the structured logs created during the execution of EVM

View file

@ -212,7 +212,7 @@ type worker struct {
snapshotMu sync.RWMutex // The lock used to protect the snapshots below snapshotMu sync.RWMutex // The lock used to protect the snapshots below
snapshotBlock *types.Block snapshotBlock *types.Block
snapshotReceipts types.Receipts snapshotReceipts types.Receipts
snapshotState *state.StateDB snapshotState vm.StateDB
// atomic status counters // atomic status counters
running atomic.Bool // The indicator whether the consensus engine is running or not. running atomic.Bool // The indicator whether the consensus engine is running or not.