From 2048f3ac2678d563fb908aa7f131f4db9793a98a Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 14:23:05 +0900 Subject: [PATCH] Modify rvgo for local context support --- rvgo/evm_test.go | 4 ++-- rvgo/fast/evm.go | 3 ++- rvgo/fast/witness.go | 32 +++++++++++++++++++++----------- rvgo/slow/vm.go | 5 +++-- rvgo/vm_go_test.go | 2 +- rvgo/vm_test.go | 2 +- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/rvgo/evm_test.go b/rvgo/evm_test.go index 1580654d..b9ca12cb 100644 --- a/rvgo/evm_test.go +++ b/rvgo/evm_test.go @@ -149,13 +149,13 @@ func stepEVM(t *testing.T, env *vm.EVM, wit *fast.StepWitness, addrs *Addresses, snap := env.StateDB.Snapshot() if wit.HasPreimage() { - input, err := wit.EncodePreimageOracleInput() + input, err := wit.EncodePreimageOracleInput(fast.LocalContext{}) require.NoError(t, err) ret, leftOverGas, err := env.Call(vm.AccountRef(addrs.Sender), addrs.Oracle, input, startingGas, big.NewInt(0)) require.NoError(t, err, "evm must not fail (ret: %x, gas: %d)", ret, startingGas-leftOverGas) } - input := wit.EncodeStepInput() + input := wit.EncodeStepInput(fast.LocalContext{}) ret, leftOverGas, err := env.Call(vm.AccountRef(addrs.Sender), addrs.RISCV, input, startingGas, big.NewInt(0)) require.NoError(t, err, "evm must not fail (ret: %x), at step %d", ret, step) diff --git a/rvgo/fast/evm.go b/rvgo/fast/evm.go index 696a0fc1..11503588 100644 --- a/rvgo/fast/evm.go +++ b/rvgo/fast/evm.go @@ -3,7 +3,8 @@ package fast import "github.com/ethereum/go-ethereum/crypto" var ( - StepBytes4 = crypto.Keccak256([]byte("step(bytes,bytes)"))[:4] + StepBytes4 = crypto.Keccak256([]byte("step(bytes,bytes,bytes32)"))[:4] CheatBytes4 = crypto.Keccak256([]byte("cheat(uint256,bytes32,bytes32,uint256)"))[:4] + CheatLocalKeyBytes4 = crypto.Keccak256([]byte("cheatLocalKey(uint256,bytes32,bytes32,uint256,bytes32)"))[:4] LoadKeccak256PreimagePartBytes4 = crypto.Keccak256([]byte("loadKeccak256PreimagePart(uint256,bytes)"))[:4] ) diff --git a/rvgo/fast/witness.go b/rvgo/fast/witness.go index 549005b8..6f47c28c 100644 --- a/rvgo/fast/witness.go +++ b/rvgo/fast/witness.go @@ -5,9 +5,12 @@ import ( "errors" "fmt" - "github.com/ethereum-optimism/optimism/op-preimage" + preimage "github.com/ethereum-optimism/optimism/op-preimage" + "github.com/ethereum/go-ethereum/common" ) +type LocalContext common.Hash + type StepWitness struct { // encoded state witness State []byte @@ -25,21 +28,27 @@ func uint64ToBytes32(v uint64) []byte { return out[:] } -func (wit *StepWitness) EncodeStepInput() []byte { +func (wit *StepWitness) EncodeStepInput(localContext LocalContext) []byte { abiStatePadding := (32 - (uint64(len(wit.State)) % 32)) % 32 + abiProofPadding := (32 - (uint64(len(wit.MemProof)) % 32)) % 32 var input []byte input = append(input, StepBytes4...) - input = append(input, uint64ToBytes32(32*2)...) // state data offset in bytes - input = append(input, uint64ToBytes32(32*2+32+uint64(len(wit.State))+abiStatePadding)...) // proof data offset in bytes - // TODO pad state data to multiple of 32 bytes - // TODO also pad proof data - - input = append(input, uint64ToBytes32(uint64(len(wit.State)))...) // state data length in bytes + // state data offset in bytes + input = append(input, uint64ToBytes32(32*3)...) + // proof data offset in bytes + input = append(input, uint64ToBytes32(32*3+32+uint64(len(wit.State))+abiStatePadding)...) + // local context in bytes + input = append(input, common.Hash(localContext).Bytes()...) + + // state data length in bytes + input = append(input, uint64ToBytes32(uint64(len(wit.State)))...) input = append(input, wit.State[:]...) input = append(input, make([]byte, abiStatePadding)...) - input = append(input, uint64ToBytes32(uint64(len(wit.MemProof)))...) // proof data length in bytes + // proof data length in bytes + input = append(input, uint64ToBytes32(uint64(len(wit.MemProof)))...) input = append(input, wit.MemProof[:]...) + input = append(input, make([]byte, abiProofPadding)...) return input } @@ -47,7 +56,7 @@ func (wit *StepWitness) HasPreimage() bool { return wit.PreimageKey != ([32]byte{}) } -func (wit *StepWitness) EncodePreimageOracleInput() ([]byte, error) { +func (wit *StepWitness) EncodePreimageOracleInput(localContext LocalContext) ([]byte, error) { if wit.PreimageKey == ([32]byte{}) { return nil, errors.New("cannot encode pre-image oracle input, witness has no pre-image to proof") } @@ -59,13 +68,14 @@ func (wit *StepWitness) EncodePreimageOracleInput() ([]byte, error) { // In production usage there should be an on-chain contract that exposes this, // rather than going through the global keccak256 oracle. var input []byte - input = append(input, CheatBytes4...) + input = append(input, CheatLocalKeyBytes4...) input = append(input, uint64ToBytes32(wit.PreimageOffset)...) input = append(input, wit.PreimageKey[:]...) var tmp [32]byte copy(tmp[:], wit.PreimageValue[wit.PreimageOffset:]) input = append(input, tmp[:]...) input = append(input, uint64ToBytes32(uint64(len(wit.PreimageValue))-8)...) + input = append(input, common.Hash(localContext).Bytes()...) // Note: we can pad calldata to 32 byte multiple, but don't strictly have to return input, nil case preimage.Keccak256KeyType: diff --git a/rvgo/slow/vm.go b/rvgo/slow/vm.go index f72141b8..b841df66 100644 --- a/rvgo/slow/vm.go +++ b/rvgo/slow/vm.go @@ -3,6 +3,7 @@ package slow import ( "encoding/binary" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -103,8 +104,8 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err // TODO: validate abi offset values? - stateContentOffset := uint8(4 + 32 + 32 + 32) - if iszero(eq(b32asBEWord(calldataload(toU64(4+32*2))), shortToU256(stateSize))) { + stateContentOffset := uint8(4 + 32 + 32 + 32 + 32) + if iszero(eq(b32asBEWord(calldataload(toU64(4+32*3))), shortToU256(stateSize))) { // user-provided state size must match expected state size panic("invalid state size input") } diff --git a/rvgo/vm_go_test.go b/rvgo/vm_go_test.go index a484b448..05400e24 100644 --- a/rvgo/vm_go_test.go +++ b/rvgo/vm_go_test.go @@ -111,7 +111,7 @@ func fullTest(t *testing.T, vmState *fast.VMState, po *testOracle, symbols fast. require.NoError(t, err) if runSlow { - slowPostHash, err := slow.Step(wit.EncodeStepInput(), po) + slowPostHash, err := slow.Step(wit.EncodeStepInput(fast.LocalContext{}), po) require.NoErrorf(t, err, "slow VM err at step %d, PC %08x: %v", i, vmState.PC, err) require.Equal(t, fastStateHash, slowPostHash, "fast post-state must match slow post-state") } diff --git a/rvgo/vm_test.go b/rvgo/vm_test.go index 081b84eb..76f96d9e 100644 --- a/rvgo/vm_test.go +++ b/rvgo/vm_test.go @@ -75,7 +75,7 @@ func runSlowTestSuite(t *testing.T, path string) { require.NoError(t, err) // Now run the same in slow mode - input := wit.EncodeStepInput() + input := wit.EncodeStepInput(fast.LocalContext{}) post, err := slow.Step(input, nil) require.NoErrorf(t, err, "slow VM err at step %d, PC %08x: %v", i, vmState.PC, err)