core/vm/runtime: utilize the programs a bit

This commit is contained in:
Martin Holst Swende 2024-11-04 14:54:48 +01:00
parent 659cd13c1f
commit 32b1831920
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 69 additions and 117 deletions

View file

@ -149,11 +149,11 @@ func (p *Program) ExtcodeCopy(address, memOffset, codeOffset, length any) *Progr
// Call is a convenience function to make a call. If 'gas' is nil, the opcode GAS will // Call is a convenience function to make a call. If 'gas' is nil, the opcode GAS will
// be used to provide all gas. // be used to provide all gas.
func (p *Program) Call(gas *big.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { func (p *Program) Call(gas *big.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program {
p.Push(outSize) if outOffset == outSize && inSize == outSize && inOffset == outSize && value == outSize {
p.Push(outOffset) p.Push(outSize).Ops(vm.DUP1, vm.DUP1, vm.DUP1, vm.DUP1)
p.Push(inSize) } else {
p.Push(inOffset) p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset).Push(value)
p.Push(value) }
p.Push(address) p.Push(address)
if gas == nil { if gas == nil {
p.Op(vm.GAS) p.Op(vm.GAS)
@ -166,10 +166,11 @@ func (p *Program) Call(gas *big.Int, address, value, inOffset, inSize, outOffset
// DelegateCall is a convenience function to make a delegatecall. If 'gas' is nil, the opcode GAS will // DelegateCall is a convenience function to make a delegatecall. If 'gas' is nil, the opcode GAS will
// be used to provide all gas. // be used to provide all gas.
func (p *Program) DelegateCall(gas *big.Int, address, inOffset, inSize, outOffset, outSize any) *Program { func (p *Program) DelegateCall(gas *big.Int, address, inOffset, inSize, outOffset, outSize any) *Program {
p.Push(outSize) if outOffset == outSize && inSize == outSize && inOffset == outSize {
p.Push(outOffset) p.Push(outSize).Ops(vm.DUP1, vm.DUP1, vm.DUP1)
p.Push(inSize) } else {
p.Push(inOffset) p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset)
}
p.Push(address) p.Push(address)
if gas == nil { if gas == nil {
p.Op(vm.GAS) p.Op(vm.GAS)
@ -182,10 +183,11 @@ func (p *Program) DelegateCall(gas *big.Int, address, inOffset, inSize, outOffse
// StaticCall is a convenience function to make a staticcall. If 'gas' is nil, the opcode GAS will // StaticCall is a convenience function to make a staticcall. If 'gas' is nil, the opcode GAS will
// be used to provide all gas. // be used to provide all gas.
func (p *Program) StaticCall(gas *big.Int, address, inOffset, inSize, outOffset, outSize any) *Program { func (p *Program) StaticCall(gas *big.Int, address, inOffset, inSize, outOffset, outSize any) *Program {
p.Push(outSize) if outOffset == outSize && inSize == outSize && inOffset == outSize {
p.Push(outOffset) p.Push(outSize).Ops(vm.DUP1, vm.DUP1, vm.DUP1)
p.Push(inSize) } else {
p.Push(inOffset) p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset)
}
p.Push(address) p.Push(address)
if gas == nil { if gas == nil {
p.Op(vm.GAS) p.Op(vm.GAS)
@ -198,10 +200,11 @@ func (p *Program) StaticCall(gas *big.Int, address, inOffset, inSize, outOffset,
// StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will // StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will
// be used to provide all gas. // be used to provide all gas.
func (p *Program) CallCode(gas *big.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { func (p *Program) CallCode(gas *big.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program {
p.Push(outSize) if outOffset == outSize && inSize == outSize && inOffset == outSize {
p.Push(outOffset) p.Push(outSize).Ops(vm.DUP1, vm.DUP1, vm.DUP1)
p.Push(inSize) } else {
p.Push(inOffset) p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset)
}
p.Push(value) p.Push(value)
p.Push(address) p.Push(address)
if gas == nil { if gas == nil {
@ -218,16 +221,17 @@ func (p *Program) Label() uint64 {
} }
// Jumpdest adds a JUMPDEST op, and returns the PC of that instruction // Jumpdest adds a JUMPDEST op, and returns the PC of that instruction
func (p *Program) Jumpdest() uint64 { func (p *Program) Jumpdest() (*Program, uint64) {
here := p.Label() here := p.Label()
p.Op(vm.JUMPDEST) p.Op(vm.JUMPDEST)
return here return p, here
} }
// Jump pushes the destination and adds a JUMP // Jump pushes the destination and adds a JUMP
func (p *Program) Jump(loc any) { func (p *Program) Jump(loc any) *Program {
p.Push(loc) p.Push(loc)
p.Op(vm.JUMP) p.Op(vm.JUMP)
return p
} }
// Jump pushes the destination and adds a JUMP // Jump pushes the destination and adds a JUMP

View file

@ -33,6 +33,7 @@ import (
"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/core/vm"
"github.com/ethereum/go-ethereum/core/vm/program"
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -436,110 +437,57 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
// BenchmarkSimpleLoop test a pretty simple loop which loops until OOG // BenchmarkSimpleLoop test a pretty simple loop which loops until OOG
// 55 ms // 55 ms
func BenchmarkSimpleLoop(b *testing.B) { func BenchmarkSimpleLoop(b *testing.B) {
staticCallIdentity := []byte{
byte(vm.JUMPDEST), // [ count ]
// push args for the call
byte(vm.PUSH1), 0, // out size
byte(vm.DUP1), // out offset
byte(vm.DUP1), // out insize
byte(vm.DUP1), // in offset
byte(vm.PUSH1), 0x4, // address of identity
byte(vm.GAS), // gas
byte(vm.STATICCALL),
byte(vm.POP), // pop return value
byte(vm.PUSH1), 0, // jumpdestination
byte(vm.JUMP),
}
callIdentity := []byte{ p, lbl := program.New().Jumpdest()
byte(vm.JUMPDEST), // [ count ] // Call identity, and pop return value
// push args for the call staticCallIdentity := p.
byte(vm.PUSH1), 0, // out size StaticCall(nil, 0x4, 0, 0, 0, 0).
byte(vm.DUP1), // out offset Op(vm.POP). // pop return value
byte(vm.DUP1), // out insize Jump(lbl). // jump to label
byte(vm.DUP1), // in offset Bytecode()
byte(vm.DUP1), // value
byte(vm.PUSH1), 0x4, // address of identity
byte(vm.GAS), // gas
byte(vm.CALL),
byte(vm.POP), // pop return value
byte(vm.PUSH1), 0, // jumpdestination
byte(vm.JUMP),
}
callInexistant := []byte{ p, lbl = program.New().Jumpdest()
byte(vm.JUMPDEST), // [ count ] callIdentity := p.
// push args for the call Call(nil, 0x4, 0, 0, 0, 0, 0).
byte(vm.PUSH1), 0, // out size Op(vm.POP). // pop return value
byte(vm.DUP1), // out offset Jump(lbl). // jump to label
byte(vm.DUP1), // out insize Bytecode()
byte(vm.DUP1), // in offset
byte(vm.DUP1), // value
byte(vm.PUSH1), 0xff, // address of existing contract
byte(vm.GAS), // gas
byte(vm.CALL),
byte(vm.POP), // pop return value
byte(vm.PUSH1), 0, // jumpdestination
byte(vm.JUMP),
}
callEOA := []byte{ p, lbl = program.New().Jumpdest()
byte(vm.JUMPDEST), // [ count ] callInexistant := p.
// push args for the call Call(nil, 0xff, 0, 0, 0, 0, 0).
byte(vm.PUSH1), 0, // out size Op(vm.POP). // pop return value
byte(vm.DUP1), // out offset Jump(lbl). // jump to label
byte(vm.DUP1), // out insize Bytecode()
byte(vm.DUP1), // in offset
byte(vm.DUP1), // value
byte(vm.PUSH1), 0xE0, // address of EOA
byte(vm.GAS), // gas
byte(vm.CALL),
byte(vm.POP), // pop return value
byte(vm.PUSH1), 0, // jumpdestination
byte(vm.JUMP),
}
loopingCode := []byte{ p, lbl = program.New().Jumpdest()
byte(vm.JUMPDEST), // [ count ] callEOA := p.
// push args for the call Call(nil, 0xE0, 0, 0, 0, 0, 0). // call addr of EOA
byte(vm.PUSH1), 0, // out size Op(vm.POP). // pop return value
byte(vm.DUP1), // out offset Jump(lbl). // jump to label
byte(vm.DUP1), // out insize Bytecode()
byte(vm.DUP1), // in offset
byte(vm.PUSH1), 0x4, // address of identity
byte(vm.GAS), // gas
byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), p, lbl = program.New().Jumpdest()
byte(vm.PUSH1), 0, // jumpdestination // Push as if we were making call, then pop it off again, and loop
byte(vm.JUMP), loopingCode := p.Push(0).
} Ops(vm.DUP1, vm.DUP1, vm.DUP1).
Push(0x4).
Ops(vm.GAS, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP).
Jump(lbl).Bytecode()
loopingCode2 := []byte{ p, lbl = program.New().Jumpdest()
byte(vm.JUMPDEST), // [ count ] loopingCode2 := p.
// push args for the call Push(0x01020304).Push(0x0102030405).
byte(vm.PUSH4), 1, 2, 3, 4, Ops(vm.POP, vm.POP).
byte(vm.PUSH5), 1, 2, 3, 4, 5, Op(vm.PUSH6).Append(make([]byte, 6)).Op(vm.JUMP). // Jumpdest zero expressed in 6 bytes
Bytecode()
byte(vm.POP), byte(vm.POP), p, lbl = program.New().Jumpdest()
byte(vm.PUSH6), 0, 0, 0, 0, 0, 0, // jumpdestination callRevertingContractWithInput := p.
byte(vm.JUMP), Call(nil, 0xee, 0, 0, 0x20, 0x0, 0x0).
} Op(vm.POP).
Jump(lbl).
callRevertingContractWithInput := []byte{ Bytecode()
byte(vm.JUMPDEST), //
// push args for the call
byte(vm.PUSH1), 0, // out size
byte(vm.DUP1), // out offset
byte(vm.PUSH1), 0x20, // in size
byte(vm.PUSH1), 0x00, // in offset
byte(vm.PUSH1), 0x00, // value
byte(vm.PUSH1), 0xEE, // address of reverting contract
byte(vm.GAS), // gas
byte(vm.CALL),
byte(vm.POP), // pop return value
byte(vm.PUSH1), 0, // jumpdestination
byte(vm.JUMP),
}
//tracer := logger.NewJSONLogger(nil, os.Stdout) //tracer := logger.NewJSONLogger(nil, os.Stdout)
//Execute(loopingCode, nil, &Config{ //Execute(loopingCode, nil, &Config{