Skip to content

Commit e38815e

Browse files
authored
Merge pull request #43 from ethereum-optimism/tip/contract-bindings
rvgo: Generate contract bindings
2 parents c623d4d + 469c174 commit e38815e

File tree

14 files changed

+1580
-58
lines changed

14 files changed

+1580
-58
lines changed

rvgo/Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,20 @@ lint-check:
3232
lint-fix:
3333
golangci-lint run --fix
3434
.PHONY: lint-fix
35+
36+
build-bindgen:
37+
cd ../rvsol/lib/optimism/op-bindings && \
38+
go build -o ./bin/op-bindings ./cmd/. && \
39+
cp ./bin/op-bindings ../../../../rvgo/
40+
.PHONY: build-bindgen
41+
42+
bindgen-generate-local:
43+
./op-bindings \
44+
generate \
45+
--metadata-out ./bindings \
46+
--bindings-package bindings \
47+
--contracts-list ../rvsol/artifacts.json \
48+
--log.level info \
49+
local \
50+
--forge-artifacts ../rvsol/out
51+
.PHONY: bindgen-generate-local

rvgo/bindings/preimageoracle.go

Lines changed: 1073 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rvgo/bindings/preimageoracle_more.go

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rvgo/bindings/registry.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package bindings
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/ethereum-optimism/superchain-registry/superchain"
8+
9+
"github.com/ethereum-optimism/optimism/op-bindings/solc"
10+
"github.com/ethereum/go-ethereum/common"
11+
)
12+
13+
// layouts represents the set of storage layouts. It is populated in an init function.
14+
var layouts = make(map[string]*solc.StorageLayout)
15+
16+
// deployedBytecodes represents the set of deployed bytecodes. It is populated
17+
// in an init function.
18+
var deployedBytecodes = make(map[string]string)
19+
20+
var initBytecodes = make(map[string]string)
21+
var deploymentSalts = make(map[string]string)
22+
var deployers = make(map[string]string)
23+
24+
// immutableReferences represents the set of immutable references. It is populated
25+
// in an init function.
26+
var immutableReferences = make(map[string]bool)
27+
28+
// Create2DeployerCodeHash represents the codehash of the Create2Deployer contract.
29+
var Create2DeployerCodeHash = common.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2")
30+
31+
func init() {
32+
code, err := superchain.LoadContractBytecode(superchain.Hash(Create2DeployerCodeHash))
33+
if err != nil {
34+
panic(err)
35+
}
36+
deployedBytecodes["Create2Deployer"] = common.Bytes2Hex(code)
37+
}
38+
39+
// GetStorageLayout returns the storage layout of a contract by name.
40+
func GetStorageLayout(name string) (*solc.StorageLayout, error) {
41+
layout := layouts[name]
42+
if layout == nil {
43+
return nil, fmt.Errorf("%s: storage layout not found", name)
44+
}
45+
return layout, nil
46+
}
47+
48+
// GetDeployedBytecode returns the deployed bytecode of a contract by name.
49+
func GetDeployedBytecode(name string) ([]byte, error) {
50+
bc := deployedBytecodes[name]
51+
if bc == "" {
52+
return nil, fmt.Errorf("%s: deployed bytecode not found", name)
53+
}
54+
55+
if !isHex(bc) {
56+
return nil, fmt.Errorf("%s: invalid deployed bytecode", name)
57+
}
58+
59+
return common.FromHex(bc), nil
60+
}
61+
62+
// HasImmutableReferences returns the immutable references of a contract by name.
63+
func HasImmutableReferences(name string) (bool, error) {
64+
has, ok := immutableReferences[name]
65+
if !ok {
66+
return false, fmt.Errorf("%s: immutable reference not found", name)
67+
}
68+
return has, nil
69+
}
70+
71+
func GetInitBytecode(name string) ([]byte, error) {
72+
bc := initBytecodes[name]
73+
if bc == "" {
74+
return nil, fmt.Errorf("%s: init bytecode not found", name)
75+
}
76+
77+
if !isHex(bc) {
78+
return nil, fmt.Errorf("%s: invalid init bytecode", name)
79+
}
80+
81+
return common.FromHex(bc), nil
82+
}
83+
84+
func GetDeployerAddress(name string) ([]byte, error) {
85+
addr := deployers[name]
86+
if addr == "" {
87+
return nil, fmt.Errorf("%s: deployer address not found", name)
88+
}
89+
90+
if !common.IsHexAddress(addr) {
91+
return nil, fmt.Errorf("%s: invalid deployer address", name)
92+
}
93+
94+
return common.FromHex(addr), nil
95+
}
96+
97+
func GetDeploymentSalt(name string) ([]byte, error) {
98+
salt := deploymentSalts[name]
99+
if salt == "" {
100+
return nil, fmt.Errorf("%s: deployment salt not found", name)
101+
}
102+
103+
if !isHex(salt) {
104+
return nil, fmt.Errorf("%s: invalid deployment salt", name)
105+
}
106+
107+
return common.FromHex(salt), nil
108+
}
109+
110+
// isHexCharacter returns bool of c being a valid hexadecimal.
111+
func isHexCharacter(c byte) bool {
112+
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
113+
}
114+
115+
// isHex validates whether each byte is valid hexadecimal string.
116+
func isHex(str string) bool {
117+
if len(str)%2 != 0 {
118+
return false
119+
}
120+
str = strings.TrimPrefix(str, "0x")
121+
122+
for _, c := range []byte(str) {
123+
if !isHexCharacter(c) {
124+
return false
125+
}
126+
}
127+
return true
128+
}

rvgo/bindings/riscv.go

Lines changed: 255 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rvgo/bindings/riscv_more.go

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rvgo/fast/evm.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

rvgo/fast/witness.go

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package fast
22

33
import (
4-
"encoding/binary"
54
"errors"
65
"fmt"
6+
"math/big"
77

8+
"github.com/ethereum-optimism/asterisc/rvgo/bindings"
89
preimage "github.com/ethereum-optimism/optimism/op-preimage"
910
"github.com/ethereum/go-ethereum/common"
1011
)
@@ -22,34 +23,16 @@ type StepWitness struct {
2223
PreimageOffset uint64
2324
}
2425

25-
func uint64ToBytes32(v uint64) []byte {
26-
var out [32]byte
27-
binary.BigEndian.PutUint64(out[32-8:], v)
28-
return out[:]
29-
}
30-
31-
func (wit *StepWitness) EncodeStepInput(localContext LocalContext) []byte {
32-
abiStatePadding := (32 - (uint64(len(wit.State)) % 32)) % 32
33-
abiProofPadding := (32 - (uint64(len(wit.MemProof)) % 32)) % 32
34-
35-
var input []byte
36-
input = append(input, StepBytes4...)
37-
// state data offset in bytes
38-
input = append(input, uint64ToBytes32(32*3)...)
39-
// proof data offset in bytes
40-
input = append(input, uint64ToBytes32(32*3+32+uint64(len(wit.State))+abiStatePadding)...)
41-
// local context in bytes
42-
input = append(input, common.Hash(localContext).Bytes()...)
43-
44-
// state data length in bytes
45-
input = append(input, uint64ToBytes32(uint64(len(wit.State)))...)
46-
input = append(input, wit.State[:]...)
47-
input = append(input, make([]byte, abiStatePadding)...)
48-
// proof data length in bytes
49-
input = append(input, uint64ToBytes32(uint64(len(wit.MemProof)))...)
50-
input = append(input, wit.MemProof[:]...)
51-
input = append(input, make([]byte, abiProofPadding)...)
52-
return input
26+
func (wit *StepWitness) EncodeStepInput(localContext LocalContext) ([]byte, error) {
27+
abi, err := bindings.RISCVMetaData.GetAbi()
28+
if err != nil {
29+
return nil, err
30+
}
31+
input, err := abi.Pack("step", wit.State, wit.MemProof, localContext)
32+
if err != nil {
33+
return nil, err
34+
}
35+
return input, nil
5336
}
5437

5538
func (wit *StepWitness) HasPreimage() bool {
@@ -61,32 +44,38 @@ func (wit *StepWitness) EncodePreimageOracleInput(localContext LocalContext) ([]
6144
return nil, errors.New("cannot encode pre-image oracle input, witness has no pre-image to proof")
6245
}
6346

47+
preimageAbi, err := bindings.PreimageOracleMetaData.GetAbi()
48+
if err != nil {
49+
return nil, err
50+
}
51+
6452
switch preimage.KeyType(wit.PreimageKey[0]) {
6553
case preimage.LocalKeyType:
6654
if len(wit.PreimageValue) > 32+8 {
6755
return nil, fmt.Errorf("local pre-image exceeds maximum size of 32 bytes with key 0x%x", wit.PreimageKey)
6856
}
69-
var input []byte
70-
input = append(input, LoadLocalDataBytes4...)
71-
input = append(input, wit.PreimageKey[:]...)
72-
input = append(input, common.Hash(localContext).Bytes()...)
73-
7457
preimagePart := wit.PreimageValue[8:]
7558
var tmp [32]byte
7659
copy(tmp[:], preimagePart)
77-
input = append(input, tmp[:]...)
78-
input = append(input, uint64ToBytes32(uint64(len(wit.PreimageValue)-8))...)
79-
input = append(input, uint64ToBytes32(wit.PreimageOffset)...)
80-
// Note: we can pad calldata to 32 byte multiple, but don't strictly have to
60+
input, err := preimageAbi.Pack("loadLocalData",
61+
new(big.Int).SetBytes(wit.PreimageKey[1:]),
62+
localContext,
63+
tmp,
64+
new(big.Int).SetUint64(uint64(len(preimagePart))),
65+
new(big.Int).SetUint64(uint64(wit.PreimageOffset)),
66+
)
67+
if err != nil {
68+
return nil, err
69+
}
8170
return input, nil
8271
case preimage.Keccak256KeyType:
83-
var input []byte
84-
input = append(input, LoadKeccak256PreimagePartBytes4...)
85-
input = append(input, uint64ToBytes32(wit.PreimageOffset)...)
86-
input = append(input, uint64ToBytes32(32+32)...) // partOffset, calldata offset
87-
input = append(input, uint64ToBytes32(uint64(len(wit.PreimageValue))-8)...)
88-
input = append(input, wit.PreimageValue[8:]...)
89-
// Note: we can pad calldata to 32 byte multiple, but don't strictly have to
72+
input, err := preimageAbi.Pack(
73+
"loadKeccak256PreimagePart",
74+
new(big.Int).SetUint64(uint64(wit.PreimageOffset)),
75+
wit.PreimageValue[8:])
76+
if err != nil {
77+
return nil, err
78+
}
9079
return input, nil
9180
default:
9281
return nil, fmt.Errorf("unsupported pre-image type %d, cannot prepare preimage with key %x offset %d for oracle",

rvgo/test/evm_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ func stepEVM(t *testing.T, env *vm.EVM, wit *fast.StepWitness, addrs *Addresses,
156156
require.NoError(t, err, "evm must not fail (ret: %x, gas: %d)", ret, startingGas-leftOverGas)
157157
}
158158

159-
input := wit.EncodeStepInput(fast.LocalContext{})
159+
input, err := wit.EncodeStepInput(fast.LocalContext{})
160+
require.NoError(t, err)
160161

161162
ret, leftOverGas, err := env.Call(vm.AccountRef(addrs.Sender), addrs.RISCV, input, startingGas, big.NewInt(0))
162163
if revertCode != nil {

rvgo/test/syscall_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ func runEVM(t *testing.T, contracts *Contracts, addrs *Addresses, stepWitness *f
3838
}
3939

4040
func runSlow(t *testing.T, stepWitness *fast.StepWitness, fastPost fast.StateWitness, po slow.PreimageOracle, expectedErr interface{}) {
41-
slowPostHash, err := slow.Step(stepWitness.EncodeStepInput(fast.LocalContext{}), po)
41+
input, err := stepWitness.EncodeStepInput(fast.LocalContext{})
42+
require.NoError(t, err)
43+
slowPostHash, err := slow.Step(input, po)
4244
if expectedErr != nil {
4345
require.ErrorAs(t, err, expectedErr)
4446
} else {

0 commit comments

Comments
 (0)