Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preparation for solidity v0.8.23 upgrade #452

Merged
merged 31 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
192edc0
core/vm: use uint256 in EVM implementation (#20787)
chfast Jun 8, 2020
06d5da0
core/vm: use pointers to operations vs. copy by value (#21336)
karalabe Jul 16, 2020
446b9e8
core/vm, params: make 2200 in line with spec (#21605)
holiman Sep 28, 2020
6077ecb
core/vm: replace repeated string with variable in tests (#22774)
aaronbuchwald Apr 30, 2021
9c8d228
core/vm: clean up contract creation error handling (#22766)
chfast May 1, 2021
7c6908b
core/vm: fix interpreter comments (#22797)
aaronbuchwald May 3, 2021
21bbe5f
core/vm: avoid duplicate log in json logger (#22825)
JekaMas May 6, 2021
7a55b9f
core/state: remove unused methods ReturnGas (#23092)
gzliudan Feb 22, 2024
f05fa00
core/vm: fix typo in comment (#23450)
gballet Aug 24, 2021
dc8cdf3
core/vm: rework jumpdest analysis benchmarks (#23499)
chfast Aug 30, 2021
f9e14af
core/vm: don't use iota for opcode definitions (#23928)
holiman Nov 18, 2021
3d3cc6c
core/vm: use proper JumpTable type (#23967)
chfast Nov 24, 2021
f7c6b1a
core/vm, core/state/snapshot: remove unused code (#23956)
holiman Nov 25, 2021
6415934
core/vm: simplify op lookup in contract (#23974)
gumb0 Nov 25, 2021
823ec33
core/vm: simplify error handling in interpreter loop (#23952)
chfast Nov 29, 2021
c097e56
core/vm: rename SHA3 instruction to KECCAK256 (#23976)
axic Nov 30, 2021
002be52
core/vm: don't copy JumpTable when no EIP mods are needed (#23977)
gumb0 Nov 30, 2021
bfbb678
core/vm: move interpreter.ReadOnly check into the opcode implementati…
axic Dec 1, 2021
b1c0386
core/vm: rename opSuicide to opSelfdestruct (#24022)
axic Dec 1, 2021
ae267d3
core/vm: remove stack.pushN (#24040)
axic Dec 3, 2021
7d3c783
core/vm: fill gaps in jump table with opUndefined (#24031)
chfast Dec 3, 2021
4c27910
core/vm: move interpreter interruption check to jump instructions (#2…
gumb0 Dec 3, 2021
fbc1cc1
core/vm: remove no-recursion option from config (24066)
holiman Dec 6, 2021
2ce3001
core/vm: remove unused code (IsStaticJump) (#24085)
axic Dec 9, 2021
6e92486
core/vm: reverse bit order in bytes of code bitmap (#24120)
chfast Dec 17, 2021
b022ba2
core/vm: make INVALID a defined opcode (#24017)
gumb0 Dec 17, 2021
ac35f0e
core/vm: clean up some dead functions (#24851)
s7v7nislands May 11, 2022
62b62da
core/vm: separate opcode group for 0x20 range (#24850)
s7v7nislands May 11, 2022
032b98e
core/vm: optimize Memory.Set32 (#24847)
qianbin May 11, 2022
8b6db6d
core/vm: better handle error on eip activation check (#25131)
qinglin89 Sep 26, 2022
b36678f
core/vm: performance tweak of `OpCode.String()` (#28453)
lmittmann Nov 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cmd/evm/json_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
log.Memory = memory.Data()
}
if !l.cfg.DisableStack {
log.Stack = stack.Data()
//TODO(@holiman) improve this
logstack := make([]*big.Int, len(stack.Data()))
for i, item := range stack.Data() {
logstack[i] = item.ToBig()
}
log.Stack = logstack
}
return l.encoder.Encode(log)
}
Expand Down
3 changes: 0 additions & 3 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,6 @@ func (self *stateObject) setBalance(amount *big.Int) {
}
}

// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *stateObject) ReturnGas(gas *big.Int) {}

func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
stateObject := newObject(db, self.address, self.data, onDirty)
if self.trie != nil {
Expand Down
32 changes: 13 additions & 19 deletions core/vm/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,47 @@
package vm

const (
set2BitsMask = uint16(0b1100_0000_0000_0000)
set3BitsMask = uint16(0b1110_0000_0000_0000)
set4BitsMask = uint16(0b1111_0000_0000_0000)
set5BitsMask = uint16(0b1111_1000_0000_0000)
set6BitsMask = uint16(0b1111_1100_0000_0000)
set7BitsMask = uint16(0b1111_1110_0000_0000)
set2BitsMask = uint16(0b11)
set3BitsMask = uint16(0b111)
set4BitsMask = uint16(0b1111)
set5BitsMask = uint16(0b1_1111)
set6BitsMask = uint16(0b11_1111)
set7BitsMask = uint16(0b111_1111)
)

// bitvec is a bit vector which maps bytes in a program.
// An unset bit means the byte is an opcode, a set bit means
// it's data (i.e. argument of PUSHxx).
type bitvec []byte

var lookup = [8]byte{
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1,
}

func (bits bitvec) set1(pos uint64) {
bits[pos/8] |= lookup[pos%8]
bits[pos/8] |= 1 << (pos % 8)
}

func (bits bitvec) setN(flag uint16, pos uint64) {
a := flag >> (pos % 8)
bits[pos/8] |= byte(a >> 8)
if b := byte(a); b != 0 {
// If the bit-setting affects the neighbouring byte, we can assign - no need to OR it,
// since it's the first write to that byte
a := flag << (pos % 8)
bits[pos/8] |= byte(a)
if b := byte(a >> 8); b != 0 {
bits[pos/8+1] = b
}
}

func (bits bitvec) set8(pos uint64) {
a := byte(0xFF >> (pos % 8))
a := byte(0xFF << (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = ^a
}

func (bits bitvec) set16(pos uint64) {
a := byte(0xFF >> (pos % 8))
a := byte(0xFF << (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = 0xFF
bits[pos/8+2] = ^a
}

// codeSegment checks if the position is in a code segment.
func (bits *bitvec) codeSegment(pos uint64) bool {
return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0
return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
}

// codeBitmap collects data locations in code.
Expand Down
58 changes: 36 additions & 22 deletions core/vm/analysis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package vm

import (
"math/bits"
"testing"

"github.com/XinFinOrg/XDPoSChain/crypto"
Expand All @@ -28,24 +29,27 @@ func TestJumpDestAnalysis(t *testing.T) {
exp byte
which int
}{
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0x40, 0},
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0x50, 0},
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, 0x7F, 0},
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 1},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0x03, 0},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x74, 0},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x00, 1},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x3F, 0},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xC0, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x7F, 0},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0xFF, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0x80, 2},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0x7f, 0},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0xA0, 1},
{[]byte{byte(PUSH32)}, 0x7F, 0},
{[]byte{byte(PUSH32)}, 0xFF, 1},
{[]byte{byte(PUSH32)}, 0xFF, 2},
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0},
{[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0},
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0},
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0},
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1},
{[]byte{byte(PUSH32)}, 0b1111_1110, 0},
{[]byte{byte(PUSH32)}, 0b1111_1111, 1},
{[]byte{byte(PUSH32)}, 0b1111_1111, 2},
{[]byte{byte(PUSH32)}, 0b1111_1111, 3},
{[]byte{byte(PUSH32)}, 0b0000_0001, 4},
}
for i, test := range tests {
ret := codeBitmap(test.code)
Expand All @@ -55,9 +59,12 @@ func TestJumpDestAnalysis(t *testing.T) {
}
}

const analysisCodeSize = 1200 * 1024

func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
// 1.4 ms
code := make([]byte, 1200000)
code := make([]byte, analysisCodeSize)
bench.SetBytes(analysisCodeSize)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
codeBitmap(code)
Expand All @@ -66,7 +73,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
}
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
// 4 ms
code := make([]byte, 1200000)
code := make([]byte, analysisCodeSize)
bench.SetBytes(analysisCodeSize)
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
crypto.Keccak256Hash(code)
Expand All @@ -77,13 +85,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
var op OpCode
bencher := func(b *testing.B) {
code := make([]byte, 32*b.N)
code := make([]byte, analysisCodeSize)
b.SetBytes(analysisCodeSize)
for i := range code {
code[i] = byte(op)
}
bits := make(bitvec, len(code)/8+1+4)
b.ResetTimer()
codeBitmapInternal(code, bits)
for i := 0; i < b.N; i++ {
for j := range bits {
bits[j] = 0
}
codeBitmapInternal(code, bits)
}
}
for op = PUSH1; op <= PUSH32; op++ {
bench.Run(op.String(), bencher)
Expand Down
27 changes: 5 additions & 22 deletions core/vm/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
package vm

import (
"math/big"

"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/holiman/uint256"
)

// calcMemSize64 calculates the required memory size, and returns
// the size and whether the result overflowed uint64
func calcMemSize64(off, l *big.Int) (uint64, bool) {
func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
if !l.IsUint64() {
return 0, true
}
Expand All @@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
// calcMemSize64WithUint calculates the required memory size, and returns
// the size and whether the result overflowed uint64
// Identical to calcMemSize64, but length is a uint64
func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
func calcMemSize64WithUint(off *uint256.Int, length64 uint64) (uint64, bool) {
// if length is zero, memsize is always zero, regardless of offset
if length64 == 0 {
return 0, false
}
// Check that offset doesn't overflow
if !off.IsUint64() {
offset64, overflow := off.Uint64WithOverflow()
if overflow {
return 0, true
}
offset64 := off.Uint64()
val := offset64 + length64
// if value < either of it's parts, then it overflowed
return val, val < offset64
Expand All @@ -64,22 +63,6 @@ func getData(data []byte, start uint64, size uint64) []byte {
return common.RightPadBytes(data[start:end], int(size))
}

// getDataBig returns a slice from the data based on the start and size and pads
// up to size with zero's. This function is overflow safe.
func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
dlen := big.NewInt(int64(len(data)))

s := math.BigMin(start, dlen)
e := math.BigMin(new(big.Int).Add(s, size), dlen)
return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
}

// bigUint64 returns the integer casted to a uint64 and returns whether it
// overflowed in the process.
func bigUint64(v *big.Int) (uint64, bool) {
return v.Uint64(), !v.IsUint64()
}

// toWordSize returns the ceiled word size required for memory expansion.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
Expand Down
16 changes: 6 additions & 10 deletions core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"math/big"

"github.com/XinFinOrg/XDPoSChain/common"
"github.com/holiman/uint256"
)

// ContractRef is a reference to the contract's backing object
Expand Down Expand Up @@ -81,11 +82,11 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
return c
}

func (c *Contract) validJumpdest(dest *big.Int) bool {
udest := dest.Uint64()
func (c *Contract) validJumpdest(dest *uint256.Int) bool {
udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
if overflow || udest >= uint64(len(c.Code)) {
return false
}
// Only JUMPDESTs allowed for destinations
Expand Down Expand Up @@ -131,16 +132,11 @@ func (c *Contract) AsDelegate() *Contract {

// GetOp returns the n'th element in the contract's byte array
func (c *Contract) GetOp(n uint64) OpCode {
return OpCode(c.GetByte(n))
}

// GetByte returns the n'th byte in the contract's byte array
func (c *Contract) GetByte(n uint64) byte {
if n < uint64(len(c.Code)) {
return c.Code[n]
return OpCode(c.Code[n])
}

return 0
return STOP
}

// Caller returns the caller of the contract.
Expand Down
2 changes: 1 addition & 1 deletion core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
// Parse the input into the Blake2b call parameters
var (
rounds = binary.BigEndian.Uint32(input[0:4])
final = (input[212] == blake2FFinalBlockBytes)
final = input[212] == blake2FFinalBlockBytes

h [8]uint64
m [16]uint64
Expand Down
11 changes: 5 additions & 6 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/XinFinOrg/XDPoSChain/params"
"github.com/holiman/uint256"
)

// EnableEIP enables the given EIP on the config.
Expand Down Expand Up @@ -51,17 +52,16 @@ func enable1884(jt *JumpTable) {
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884

// New opcode
jt[SELFBALANCE] = operation{
jt[SELFBALANCE] = &operation{
execute: opSelfBalance,
constantGas: GasFastStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true,
}
}

func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
callContext.stack.push(balance)
return nil, nil
}
Expand All @@ -70,18 +70,17 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
func enable1344(jt *JumpTable) {
// New opcode
jt[CHAINID] = operation{
jt[CHAINID] = &operation{
execute: opChainID,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true,
}
}

// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainId)
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainId)
callContext.stack.push(chainId)
return nil, nil
}
Expand Down
4 changes: 4 additions & 0 deletions core/vm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ var (
ErrWriteProtection = errors.New("write protection")
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
ErrGasUintOverflow = errors.New("gas uint64 overflow")

// errStopToken is an internal token indicating interpreter loop termination,
// never returned to outside callers.
errStopToken = errors.New("stop token")
)

// ErrStackUnderflow wraps an evm error when the items on the stack less
Expand Down
Loading