program

package
v1.14.6-0...-341647f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 19, 2024 License: GPL-3.0 Imports: 4 Imported by: 0

README

What is this

In many cases, we have a need to create somewhat nontrivial bytecode, for testing various quirks related to state transition or evm execution.

For example, we want to have a CREATE2- op create a contract, which is then invoked, and when invoked does a selfdestruct-to-self.

It is overkill to go full solidity, but it is also a bit tricky do assemble this by concatenating bytes.

This utility takes an approach from goevmlab where it has been used for several years, a go-lang utility to assemble evm bytecode.

Using this utility, the case above can be expressed as:

	// Some runtime code
	runtime := program.New().Ops(vm.ADDRESS, vm.SELFDESTRUCT).Bytecode()
	// A constructor returning the runtime code
	initcode := program.New().ReturnData(runtime).Bytecode()
	// A factory invoking the constructor
	outer := program.New().Create2AndCall(initcode, nil).Bytecode()

Warning

This package is a utility for testing, not for production. As such:

  • There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning
  • There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV.
  • There are no stability-guarantees. The utility will panic if the inputs do not align / make sense.

Documentation

Overview

package program is a utility to create EVM bytecode for testing, but _not_ for production. As such:

- There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning - There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV. - There are no stability-guarantees. The utility will `panic` if the inputs do not align / make sense.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Program

type Program struct {
	// contains filtered or unexported fields
}

Program is a simple bytecode container. It can be used to construct simple EVM programs. Errors during construction of a Program typically cause panics: so avoid using these programs in production settings or on untrusted input. This package is mainly meant to aid in testing. This is not a production -level "compiler".

func New

func New() *Program

New creates a new Program

func (*Program) Append

func (p *Program) Append(data []byte) *Program

Append appends the given data to the code.

func (*Program) Bytes

func (p *Program) Bytes() []byte

Bytes returns the Program bytecode. OBS: This is not a copy.

func (*Program) Call

func (p *Program) Call(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program

Call is a convenience function to make a call. If 'gas' is nil, the opcode GAS will be used to provide all gas.

func (*Program) CallCode

func (p *Program) CallCode(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program

StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will be used to provide all gas.

func (*Program) Create2

func (p *Program) Create2(code []byte, salt any) *Program

Create2 uses create2 to construct a contract with the given bytecode. This operation leaves either '0' or address on the stack.

func (*Program) Create2ThenCall

func (p *Program) Create2ThenCall(code []byte, salt any) *Program

Create2ThenCall calls create2 with the given initcode and salt, and then calls into the created contract (or calls into zero, if the creation failed).

func (*Program) DelegateCall

func (p *Program) DelegateCall(gas *uint256.Int, address, inOffset, inSize, outOffset, outSize any) *Program

DelegateCall is a convenience function to make a delegatecall. If 'gas' is nil, the opcode GAS will be used to provide all gas.

func (*Program) ExtcodeCopy

func (p *Program) ExtcodeCopy(address, memOffset, codeOffset, length any) *Program

ExtcodeCopy performs an extcodecopy invocation.

func (*Program) Hex

func (p *Program) Hex() string

Hex returns the Program bytecode as a hex string.

func (*Program) InputAddressToStack

func (p *Program) InputAddressToStack(inputOffset uint32) *Program

InputAddressToStack stores the input (calldata) to memory as address (20 bytes).

func (*Program) Jump

func (p *Program) Jump(loc any) *Program

Jump pushes the destination and adds a JUMP.

func (*Program) JumpIf

func (p *Program) JumpIf(loc any, condition any) *Program

JumpIf implements JUMPI.

func (*Program) Jumpdest

func (p *Program) Jumpdest() (*Program, uint64)

Jumpdest adds a JUMPDEST op, and returns the PC of that instruction.

func (*Program) Label

func (p *Program) Label() uint64

Label returns the PC (of the next instruction).

func (*Program) MemToStorage

func (p *Program) MemToStorage(memStart, memSize, startSlot int) *Program

MemToStorage copies the given memory area into SSTORE slots, It expects data to be aligned to 32 byte, and does not zero out remainders if some data is not I.e, if given a 1-byte area, it will still copy the full 32 bytes to storage.

func (*Program) Mstore

func (p *Program) Mstore(data []byte, memStart uint32) *Program

MStore stores the provided data (into the memory area starting at memStart).

func (*Program) MstoreSmall

func (p *Program) MstoreSmall(data []byte, memStart uint32) *Program

MstoreSmall stores the provided data, which must be smaller than 32 bytes, into the memory area starting at memStart. The data will be LHS zero-added to align on 32 bytes. For example, providing data 0x1122, it will do a PUSH2: PUSH2 0x1122, resulting in stack: 0x0000000000000000000000000000000000000000000000000000000000001122 followed by MSTORE(0,0) And thus, the resulting memory will be [ 0000000000000000000000000000000000000000000000000000000000001122 ]

func (*Program) Op

func (p *Program) Op(ops ...vm.OpCode) *Program

Op appends the given opcode(s).

func (*Program) Push

func (p *Program) Push(val any) *Program

Push creates a PUSHX instruction with the data provided. If zero is being pushed, PUSH0 will be avoided in favour of [PUSH1 0], to ensure backwards compatibility.

func (*Program) Push0

func (p *Program) Push0() *Program

Push0 implements PUSH0 (0x5f).

func (*Program) Return

func (p *Program) Return(offset, len int) *Program

Return implements RETURN

func (*Program) ReturnData

func (p *Program) ReturnData(data []byte) *Program

ReturnData loads the given data into memory, and does a return with it

func (*Program) ReturnViaCodeCopy

func (p *Program) ReturnViaCodeCopy(data []byte) *Program

ReturnViaCodeCopy utilises CODECOPY to place the given data in the bytecode of p, loads into memory (offset 0) and returns the code. This is a typical "constructor". Note: since all indexing is calculated immediately, the preceding bytecode must not be expanded or shortened.

func (*Program) Selfdestruct

func (p *Program) Selfdestruct(beneficiary any) *Program

Selfdestruct pushes beneficiary and invokes selfdestruct.

func (*Program) SetBytes

func (p *Program) SetBytes(code []byte)

SetBytes sets the Program bytecode. The combination of Bytes and SetBytes means that external callers can implement missing functionality:

...
prog.Push(1)
code := prog.Bytes()
manipulate(code)
prog.SetBytes(code)

func (*Program) Size

func (p *Program) Size() int

Size returns the current size of the bytecode.

func (*Program) Sstore

func (p *Program) Sstore(slot any, value any) *Program

Sstore stores the given byte array to the given slot. OBS! Does not verify that the value indeed fits into 32 bytes. If it does not, it will panic later on via doPush.

func (*Program) StaticCall

func (p *Program) StaticCall(gas *uint256.Int, address, inOffset, inSize, outOffset, outSize any) *Program

StaticCall is a convenience function to make a staticcall. If 'gas' is nil, the opcode GAS will be used to provide all gas.

func (*Program) Tstore

func (p *Program) Tstore(slot any, value any) *Program

Tstore stores the given byte array to the given t-slot. OBS! Does not verify that the value indeed fits into 32 bytes. If it does not, it will panic later on via doPush.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL