Commit e5014d71 authored by clabby's avatar clabby

Add VM status to alphabet game

chore: gas snapshot

Ignore vm status when comparing step result
parent e2c29255
This diff is collapsed.
......@@ -9,11 +9,11 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const AlphabetVMStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"test/FaultDisputeGame.t.sol:AlphabetVM\",\"label\":\"oracle\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_contract(IPreimageOracle)1001\"}],\"types\":{\"t_contract(IPreimageOracle)1001\":{\"encoding\":\"inplace\",\"label\":\"contract IPreimageOracle\",\"numberOfBytes\":\"20\"}}}"
const AlphabetVMStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"test/FaultDisputeGame.t.sol:AlphabetVM\",\"label\":\"oracle\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_contract(IPreimageOracle)1002\"},{\"astId\":1001,\"contract\":\"test/FaultDisputeGame.t.sol:AlphabetVM\",\"label\":\"traceLength\",\"offset\":20,\"slot\":\"0\",\"type\":\"t_uint8\"}],\"types\":{\"t_contract(IPreimageOracle)1002\":{\"encoding\":\"inplace\",\"label\":\"contract IPreimageOracle\",\"numberOfBytes\":\"20\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}"
var AlphabetVMStorageLayout = new(solc.StorageLayout)
var AlphabetVMDeployedBin = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80637dc0d1d01461003b578063f8e0cb9614610085575b600080fd5b60005461005b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61009861009336600461020a565b6100a6565b60405190815260200161007c565b60008060007f000000000000000000000000000000000000000000000000000000000000000087876040516100dc929190610276565b60405180910390200361010057600091506100f986880188610286565b905061011f565b61010c8688018861029f565b90925090508161011b816102f0565b9250505b8161012b826001610328565b604080516020810193909352820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f010000000000000000000000000000000000000000000000000000000000000017979650505050505050565b60008083601f8401126101d357600080fd5b50813567ffffffffffffffff8111156101eb57600080fd5b60208301915083602082850101111561020357600080fd5b9250929050565b6000806000806040858703121561022057600080fd5b843567ffffffffffffffff8082111561023857600080fd5b610244888389016101c1565b9096509450602087013591508082111561025d57600080fd5b5061026a878288016101c1565b95989497509550505050565b8183823760009101908152919050565b60006020828403121561029857600080fd5b5035919050565b600080604083850312156102b257600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610321576103216102c1565b5060010190565b6000821982111561033b5761033b6102c1565b50019056fea164736f6c634300080f000a"
var AlphabetVMDeployedBin = "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80637dc0d1d014610051578063a13060eb1461009b578063a8a8b5eb146100d2578063f8e0cb961461012e575b600080fd5b6000546100719073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6000546100c09074010000000000000000000000000000000000000000900460ff1681565b60405160ff9091168152602001610092565b61012c6100e036600461028f565b6000805460ff90921674010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b005b61014161013c366004610302565b61014f565b604051908152602001610092565b600080600060087f0000000000000000000000000000000000000000000000000000000000000000901b6008888860405161018b92919061036e565b6040518091039020901b036101b157600091506101aa8688018861037e565b90506101d0565b6101bd86880188610397565b9092509050816101cc816103e8565b9250505b816101dc826001610420565b60408051602081019390935282015260600160405160208183030381529060405280519060200120925060006001600060149054906101000a900460ff166102249190610438565b60ff16830361023557506001610275565b60005461025f9060019074010000000000000000000000000000000000000000900460ff16610438565b60ff1683101561027157506003610275565b5060025b8060f81b60ff60f81b198516179350505050949350505050565b6000602082840312156102a157600080fd5b813560ff811681146102b257600080fd5b9392505050565b60008083601f8401126102cb57600080fd5b50813567ffffffffffffffff8111156102e357600080fd5b6020830191508360208285010111156102fb57600080fd5b9250929050565b6000806000806040858703121561031857600080fd5b843567ffffffffffffffff8082111561033057600080fd5b61033c888389016102b9565b9096509450602087013591508082111561035557600080fd5b50610362878288016102b9565b95989497509550505050565b8183823760009101908152919050565b60006020828403121561039057600080fd5b5035919050565b600080604083850312156103aa57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610419576104196103b9565b5060010190565b60008219821115610433576104336103b9565b500190565b600060ff821660ff841680821015610452576104526103b9565b9003939250505056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(AlphabetVMStorageLayoutJSON), AlphabetVMStorageLayout); err != nil {
......
This diff is collapsed.
......@@ -15,7 +15,6 @@ import (
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)
......@@ -164,17 +163,16 @@ type PrestateLoader interface {
// ValidateAbsolutePrestate validates the absolute prestate of the fault game.
func ValidateAbsolutePrestate(ctx context.Context, trace types.TraceProvider, loader PrestateLoader) error {
providerPrestate, err := trace.AbsolutePreState(ctx)
providerPrestateHash, err := trace.AbsolutePreStateCommitment(ctx)
if err != nil {
return fmt.Errorf("failed to get the trace provider's absolute prestate: %w", err)
}
providerPrestateHash := crypto.Keccak256(providerPrestate)
onchainPrestate, err := loader.FetchAbsolutePrestateHash(ctx)
if err != nil {
return fmt.Errorf("failed to get the onchain absolute prestate: %w", err)
}
if !bytes.Equal(providerPrestateHash, onchainPrestate[:]) {
return fmt.Errorf("trace provider's absolute prestate does not match onchain absolute prestate: Provider: %s | Chain %s", common.Bytes2Hex(providerPrestateHash), onchainPrestate.Hex())
if !bytes.Equal(providerPrestateHash[:], onchainPrestate[:]) {
return fmt.Errorf("trace provider's absolute prestate does not match onchain absolute prestate: Provider: %s | Chain %s", providerPrestateHash.Hex(), onchainPrestate.Hex())
}
return nil
}
......@@ -6,6 +6,7 @@ import (
"fmt"
"testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/common"
......@@ -119,6 +120,7 @@ func TestValidateAbsolutePrestate(t *testing.T) {
t.Run("ValidPrestates", func(t *testing.T) {
prestate := []byte{0x00, 0x01, 0x02, 0x03}
prestateHash := crypto.Keccak256(prestate)
prestateHash[0] = mipsevm.VMStatusUnfinished
mockTraceProvider := newMockTraceProvider(false, prestate)
mockLoader := newMockPrestateLoader(false, common.BytesToHash(prestateHash))
err := ValidateAbsolutePrestate(context.Background(), mockTraceProvider, mockLoader)
......@@ -209,6 +211,16 @@ func (m *mockTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error
}
return m.prestate, nil
}
func (m *mockTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (common.Hash, error) {
prestate, err := m.AbsolutePreState(ctx)
if err != nil {
return common.Hash{}, err
}
hash := common.BytesToHash(crypto.Keccak256(prestate))
hash[0] = mipsevm.VMStatusUnfinished
return hash, nil
}
// StateHash computes the state-hash of the given state, or returns an error if the state is invalid.
func (m *mockTraceProvider) StateHash(ctx context.Context, state []byte) (common.Hash, error) {
......
package solver
import (
"bytes"
"context"
"errors"
"fmt"
......@@ -132,7 +133,7 @@ func (s *Solver) defend(ctx context.Context, claim types.Claim) (*types.Claim, e
// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider].
func (s *Solver) agreeWithClaim(ctx context.Context, claim types.ClaimData) (bool, error) {
ourValue, err := s.traceAtPosition(ctx, claim.Position)
return ourValue == claim.Value, err
return bytes.Equal(ourValue[1:], claim.Value[1:]), err
}
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
......
......@@ -59,7 +59,7 @@ func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash
if err != nil {
return common.Hash{}, err
}
return alphabetStateHash(claimBytes), nil
return ap.alphabetStateHash(claimBytes), nil
}
// AbsolutePreState returns the absolute pre-state for the alphabet trace.
......@@ -67,8 +67,18 @@ func (ap *AlphabetTraceProvider) AbsolutePreState(ctx context.Context) ([]byte,
return common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060"), nil
}
func (ap *AlphabetTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (common.Hash, error) {
prestate, err := ap.AbsolutePreState(ctx)
if err != nil {
return common.Hash{}, err
}
hash := common.BytesToHash(crypto.Keccak256(prestate))
hash[0] = mipsevm.VMStatusUnfinished
return hash, nil
}
func (ap *AlphabetTraceProvider) StateHash(ctx context.Context, state []byte) (common.Hash, error) {
return alphabetStateHash(state), nil
return ap.alphabetStateHash(state), nil
}
// BuildAlphabetPreimage constructs the claim bytes for the index and state item.
......@@ -76,10 +86,18 @@ func BuildAlphabetPreimage(i uint64, letter string) []byte {
return append(IndexToBytes(i), LetterToBytes(letter)...)
}
func alphabetStateHash(state []byte) common.Hash {
func (ap *AlphabetTraceProvider) alphabetStateHash(state []byte) common.Hash {
h := crypto.Keccak256Hash(state)
// In the alphabet game, we ignore the VM status code and always set it to 1.
h[0] = mipsevm.VMStatusInvalid
// instead of the state containing an "exited" boolean, we just check if the index reached the end
i := new(big.Int).SetBytes(state[:32])
finalStateIdx := uint64(len(ap.state) - 1)
if !i.IsUint64() || i.Uint64() > finalStateIdx {
h[0] = mipsevm.VMStatusPanic // this state should never be reached, if we increment by 1 per step
} else if i.Uint64() == finalStateIdx {
h[0] = mipsevm.VMStatusInvalid
} else {
h[0] = mipsevm.VMStatusUnfinished
}
return h
}
......
......@@ -9,8 +9,8 @@ import (
"github.com/stretchr/testify/require"
)
func alphabetClaim(index uint64, letter string) common.Hash {
return alphabetStateHash(BuildAlphabetPreimage(index, letter))
func alphabetClaim(index uint64, letter string, provider *AlphabetTraceProvider) common.Hash {
return provider.alphabetStateHash(BuildAlphabetPreimage(index, letter))
}
// TestAlphabetProvider_Get_ClaimsByTraceIndex tests the [fault.AlphabetProvider] Get function.
......@@ -25,15 +25,15 @@ func TestAlphabetProvider_Get_ClaimsByTraceIndex(t *testing.T) {
}{
{
7,
alphabetClaim(7, "h"),
alphabetClaim(7, "h", canonicalProvider),
},
{
3,
alphabetClaim(3, "d"),
alphabetClaim(3, "d", canonicalProvider),
},
{
5,
alphabetClaim(5, "f"),
alphabetClaim(5, "f", canonicalProvider),
},
}
......@@ -80,7 +80,7 @@ func TestGet_Succeeds(t *testing.T) {
ap := NewTraceProvider("abc", 2)
claim, err := ap.Get(context.Background(), 0)
require.NoError(t, err)
expected := alphabetClaim(0, "a")
expected := alphabetClaim(0, "a", ap)
require.Equal(t, expected, claim)
}
......@@ -98,6 +98,6 @@ func TestGet_Extends(t *testing.T) {
ap := NewTraceProvider("abc", 2)
claim, err := ap.Get(context.Background(), 3)
require.NoError(t, err)
expected := alphabetClaim(2, "c")
expected := alphabetClaim(2, "c", ap)
require.Equal(t, expected, claim)
}
......@@ -123,6 +123,14 @@ func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, err
return state.EncodeWitness(), nil
}
func (p *CannonTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (common.Hash, error) {
state, err := p.AbsolutePreState(ctx)
if err != nil {
return common.Hash{}, fmt.Errorf("cannot load absolute pre-state: %w", err)
}
return mipsevm.StateWitness(state).StateHash(), nil
}
// loadProof will attempt to load or generate the proof data at the specified index
// If the requested index is beyond the end of the actual trace it is extended with no-op instructions.
func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) {
......
......@@ -106,6 +106,9 @@ type TraceProvider interface {
// AbsolutePreState is the pre-image value of the trace that transitions to the trace value at index 0
AbsolutePreState(ctx context.Context) (preimage []byte, err error)
// AbsolutePreStateCommitment is the commitment of the pre-image value of the trace that transitions to the trace value at index 0
AbsolutePreStateCommitment(ctx context.Context) (hash common.Hash, err error)
// StateHash computes the state-hash of the given state, or returns an error if the state is invalid.
StateHash(ctx context.Context, state []byte) (common.Hash, error)
}
......
......@@ -88,16 +88,16 @@ FaucetTest:test_nonAdmin_drip_fails() (gas: 262520)
FaucetTest:test_receive_succeeds() (gas: 17401)
FaucetTest:test_withdraw_nonAdmin_reverts() (gas: 13145)
FaucetTest:test_withdraw_succeeds() (gas: 78359)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 499188)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 506048)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 502729)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505946)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 505215)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 497953)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 504813)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 501494)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 502711)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 501980)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 509676)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 516934)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 513235)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 516475)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 514814)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 508441)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 515699)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 512000)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 513240)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 511579)
FaultDisputeGame_Test:test_addLocalData_static_succeeds() (gas: 640504)
FaultDisputeGame_Test:test_createdAt_succeeds() (gas: 10342)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 32377)
......
......@@ -43,7 +43,7 @@
"eip1559Elasticity": 6,
"l1GenesisBlockTimestamp": "0x64c811bf",
"l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": "0x41c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 30,
"faultGameMaxDuration": 1200,
"systemConfigStartBlock": 0
......
......@@ -16,7 +16,7 @@
"src/L2/L2StandardBridge.sol": "0xe025dcccbf21d48828ecf588941c9ba04c91b87bdd177a653d3f1b265b0b02a8",
"src/L2/L2ToL1MessagePasser.sol": "0xda56ba2e5b2c28fa8ca2df24077d49e96155a00ecc99cd0778d681be6ed166fe",
"src/L2/SequencerFeeVault.sol": "0x37816035c992d38cf7e3d5a1846b02d017dd7bdca46abe6e5c5171b9ee6225ab",
"src/dispute/FaultDisputeGame.sol": "0xf990d243b117e7ba7e765e1aee433adcd01cf20dcc7088065691b09ae204ae47",
"src/dispute/FaultDisputeGame.sol": "0xb965888c2ea9e8dda89d6b5041c05b445568c8819b6616bba15ecf61fa112045",
"src/legacy/DeployerWhitelist.sol": "0xf2129ec3da75307ba8e21bc943c332bb04704642e6e263149b5c8ee92dbcb7a8",
"src/legacy/L1BlockNumber.sol": "0x30aae1fc85103476af0226b6e98c71c01feebbdc35d93401390b1ad438a37be6",
"src/legacy/LegacyMessagePasser.sol": "0x5c08b0a663cc49d30e4e38540f6aefab19ef287c3ecd31c8d8c3decd5f5bd497",
......
......@@ -151,7 +151,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// preimage of the prestate claim hash.
// We ignore the highest order byte of the digest because it is used to
// indicate the VM Status and is added after the digest is computed.
if (cleanHighByte(keccak256(_stateData)) != cleanHighByte(Claim.unwrap(preStateClaim))) {
if (keccak256(_stateData) << 8 != Claim.unwrap(preStateClaim) << 8) {
revert InvalidPrestate();
}
......@@ -167,7 +167,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// SAFETY: While the `attack` path does not need an extra check for the post
// state's depth in relation to the parent, we don't need another
// branch because (n - n) % 2 == 0.
bool validStep = VM.step(_stateData, _proof) == Claim.unwrap(postState.claim);
// We ignore the highest order byte of the digest because it is used to
// indicate the VM Status and is added after the digest is computed. The
// hash commits to the exit code and the exit status, so the VM status does
// not need to be checked for equivalence.
bool validStep = (VM.step(_stateData, _proof)) << 8 == (Claim.unwrap(postState.claim) << 8);
bool parentPostAgree = (parentPos.depth() - postState.position.depth()) % 2 == 0;
if (parentPostAgree == validStep) revert ValidStep();
......@@ -541,13 +545,4 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
ancestor_ = claimData[ancestor_.parentIndex];
}
}
/// @notice Cleans the highest order byte of a given fixed bytes value.
/// @param _in The bytes32 value to clean.
/// @return out_ The cleaned bytes32 value.
function cleanHighByte(bytes32 _in) internal pure returns (bytes32 out_) {
assembly {
out_ := and(not(shl(248, 0xFF)), _in)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment