Commit c36b3d94 authored by Andreas Bigger's avatar Andreas Bigger

Fix up the cannon updater with tests

parent 2b0c5664
...@@ -21,11 +21,12 @@ const ( ...@@ -21,11 +21,12 @@ const (
) )
type proofData struct { type proofData struct {
ClaimValue hexutil.Bytes `json:"post"` ClaimValue hexutil.Bytes `json:"post"`
StateData hexutil.Bytes `json:"state-data"` StateData hexutil.Bytes `json:"state-data"`
ProofData hexutil.Bytes `json:"proof-data"` ProofData hexutil.Bytes `json:"proof-data"`
OracleKey hexutil.Bytes `json:"oracle-key,omitempty"` OracleKey hexutil.Bytes `json:"oracle-key,omitempty"`
OracleValue hexutil.Bytes `json:"oracle-value,omitempty"` OracleValue hexutil.Bytes `json:"oracle-value,omitempty"`
OracleOffset uint32 `json:"oracle-offset,omitempty"`
} }
type ProofGenerator interface { type ProofGenerator interface {
...@@ -52,7 +53,7 @@ func (p *CannonTraceProvider) GetOracleData(ctx context.Context, i uint64) (*typ ...@@ -52,7 +53,7 @@ func (p *CannonTraceProvider) GetOracleData(ctx context.Context, i uint64) (*typ
if err != nil { if err != nil {
return nil, err return nil, err
} }
data := types.NewPreimageOracleData(proof.OracleKey, proof.OracleValue) data := types.NewPreimageOracleData(proof.OracleKey, proof.OracleValue, proof.OracleOffset)
return &data, nil return &data, nil
} }
......
...@@ -66,7 +66,7 @@ func (u *cannonUpdater) UpdateOracle(ctx context.Context, data types.PreimageOra ...@@ -66,7 +66,7 @@ func (u *cannonUpdater) UpdateOracle(ctx context.Context, data types.PreimageOra
// sendLocalOracleData sends the local oracle data to the [txmgr]. // sendLocalOracleData sends the local oracle data to the [txmgr].
func (u *cannonUpdater) sendLocalOracleData(ctx context.Context, data types.PreimageOracleData) error { func (u *cannonUpdater) sendLocalOracleData(ctx context.Context, data types.PreimageOracleData) error {
txData, err := u.buildLocalOracleData(data) txData, err := u.BuildLocalOracleData(data)
if err != nil { if err != nil {
return fmt.Errorf("local oracle tx data build: %w", err) return fmt.Errorf("local oracle tx data build: %w", err)
} }
...@@ -75,32 +75,32 @@ func (u *cannonUpdater) sendLocalOracleData(ctx context.Context, data types.Prei ...@@ -75,32 +75,32 @@ func (u *cannonUpdater) sendLocalOracleData(ctx context.Context, data types.Prei
// sendGlobalOracleData sends the global oracle data to the [txmgr]. // sendGlobalOracleData sends the global oracle data to the [txmgr].
func (u *cannonUpdater) sendGlobalOracleData(ctx context.Context, data types.PreimageOracleData) error { func (u *cannonUpdater) sendGlobalOracleData(ctx context.Context, data types.PreimageOracleData) error {
txData, err := u.buildGlobalOracleData(data) txData, err := u.BuildGlobalOracleData(data)
if err != nil { if err != nil {
return fmt.Errorf("global oracle tx data build: %w", err) return fmt.Errorf("global oracle tx data build: %w", err)
} }
return u.sendTxAndWait(ctx, u.fdgAddr, txData) return u.sendTxAndWait(ctx, u.fdgAddr, txData)
} }
// buildLocalOracleData takes the local preimage key and data // BuildLocalOracleData takes the local preimage key and data
// and creates tx data to load the key, data pair into the // and creates tx data to load the key, data pair into the
// PreimageOracle contract from the FaultDisputeGame contract call. // PreimageOracle contract from the FaultDisputeGame contract call.
func (u *cannonUpdater) buildLocalOracleData(data types.PreimageOracleData) ([]byte, error) { func (u *cannonUpdater) BuildLocalOracleData(data types.PreimageOracleData) ([]byte, error) {
return u.fdgAbi.Pack( return u.fdgAbi.Pack(
"addLocalData", "addLocalData",
data.OracleKey, data.GetIdent(),
big.NewInt(0), big.NewInt(int64(data.OracleOffset)),
) )
} }
// buildGlobalOracleData takes the global preimage key and data // BuildGlobalOracleData takes the global preimage key and data
// and creates tx data to load the key, data pair into the // and creates tx data to load the key, data pair into the
// PreimageOracle contract. // PreimageOracle contract.
func (u *cannonUpdater) buildGlobalOracleData(data types.PreimageOracleData) ([]byte, error) { func (u *cannonUpdater) BuildGlobalOracleData(data types.PreimageOracleData) ([]byte, error) {
return u.preimageOracleAbi.Pack( return u.preimageOracleAbi.Pack(
"loadKeccak256PreimagePart", "loadKeccak256PreimagePart",
big.NewInt(0), big.NewInt(int64(data.OracleOffset)),
data.OracleData, data.GetPreimageWithoutSize(),
) )
} }
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
...@@ -13,6 +14,7 @@ import ( ...@@ -13,6 +14,7 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -25,14 +27,15 @@ var ( ...@@ -25,14 +27,15 @@ var (
) )
type mockTxManager struct { type mockTxManager struct {
from common.Address from common.Address
sends int sends int
calls int failedSends int
sendFails bool sendFails bool
} }
func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (*ethtypes.Receipt, error) { func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (*ethtypes.Receipt, error) {
if m.sendFails { if m.sendFails {
m.failedSends++
return nil, mockSendError return nil, mockSendError
} }
m.sends++ m.sends++
...@@ -44,11 +47,7 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) ( ...@@ -44,11 +47,7 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (
} }
func (m *mockTxManager) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) { func (m *mockTxManager) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
if m.sendFails { panic("not implemented")
return nil, mockSendError
}
m.calls++
return []byte{}, nil
} }
func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) { func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) {
...@@ -74,14 +73,68 @@ func newTestCannonUpdater(t *testing.T, sendFails bool) (*cannonUpdater, *mockTx ...@@ -74,14 +73,68 @@ func newTestCannonUpdater(t *testing.T, sendFails bool) (*cannonUpdater, *mockTx
// UpdateOracle function. // UpdateOracle function.
func TestCannonUpdater_UpdateOracle(t *testing.T) { func TestCannonUpdater_UpdateOracle(t *testing.T) {
t.Run("succeeds", func(t *testing.T) { t.Run("succeeds", func(t *testing.T) {
_, _ = newTestCannonUpdater(t, false) updater, mockTxMgr := newTestCannonUpdater(t, false)
// require.Nil(t, updater.UpdateOracle(context.Background(), types.PreimageOracleData{})) require.Nil(t, updater.UpdateOracle(context.Background(), types.PreimageOracleData{
// require.Equal(t, 1, mockTxMgr.calls) OracleData: common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
}))
require.Equal(t, 1, mockTxMgr.sends)
}) })
t.Run("send fails", func(t *testing.T) { t.Run("send fails", func(t *testing.T) {
_, _ = newTestCannonUpdater(t, true) updater, mockTxMgr := newTestCannonUpdater(t, true)
// require.Error(t, updater.UpdateOracle(context.Background(), types.PreimageOracleData{})) require.Error(t, updater.UpdateOracle(context.Background(), types.PreimageOracleData{
// require.Equal(t, 1, mockTxMgr.calls) OracleData: common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
}))
require.Equal(t, 1, mockTxMgr.failedSends)
}) })
} }
// TestCannonUpdater_BuildLocalOracleData tests the [cannonUpdater]
// builds a valid tx candidate for a local oracle update.
func TestCannonUpdater_BuildLocalOracleData(t *testing.T) {
updater, _ := newTestCannonUpdater(t, false)
oracleData := types.PreimageOracleData{
OracleKey: common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
OracleData: common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
OracleOffset: 7,
}
txData, err := updater.BuildLocalOracleData(oracleData)
require.NoError(t, err)
var addLocalDataBytes4 = crypto.Keccak256([]byte("addLocalData(uint256,uint256)"))[:4]
// Pack the tx data manually.
var expected []byte
expected = append(expected, addLocalDataBytes4...)
expected = append(expected, common.Hex2Bytes("00aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")...)
expected = append(expected, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000007")...)
require.Equal(t, expected, txData)
}
// TestCannonUpdater_BuildGlobalOracleData tests the [cannonUpdater]
// builds a valid tx candidate for a global oracle update.
func TestCannonUpdater_BuildGlobalOracleData(t *testing.T) {
updater, _ := newTestCannonUpdater(t, false)
oracleData := types.PreimageOracleData{
OracleKey: common.Hex2Bytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
OracleData: common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
OracleOffset: 7,
}
txData, err := updater.BuildGlobalOracleData(oracleData)
require.NoError(t, err)
var loadKeccak256PreimagePartBytes4 = crypto.Keccak256([]byte("loadKeccak256PreimagePart(uint256,bytes)"))[:4]
// Pack the tx data manually.
var expected []byte
expected = append(expected, loadKeccak256PreimagePartBytes4...)
expected = append(expected, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000007")...)
expected = append(expected, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")...)
expected = append(expected, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000018")...)
expected = append(expected, common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccc0000000000000000")...)
require.Equal(t, expected, txData)
}
...@@ -37,6 +37,6 @@ func (a *alphabetWithProofProvider) GetOracleData(ctx context.Context, i uint64) ...@@ -37,6 +37,6 @@ func (a *alphabetWithProofProvider) GetOracleData(ctx context.Context, i uint64)
if a.OracleError != nil { if a.OracleError != nil {
return &types.PreimageOracleData{}, a.OracleError return &types.PreimageOracleData{}, a.OracleError
} }
data := types.NewPreimageOracleData([]byte{byte(i)}, []byte{byte(i)}) data := types.NewPreimageOracleData([]byte{byte(i)}, []byte{byte(i)}, uint32(i))
return &data, nil return &data, nil
} }
...@@ -23,22 +23,34 @@ const ( ...@@ -23,22 +23,34 @@ const (
// PreimageOracleData encapsulates the preimage oracle data // PreimageOracleData encapsulates the preimage oracle data
// to load into the onchain oracle. // to load into the onchain oracle.
type PreimageOracleData struct { type PreimageOracleData struct {
IsLocal bool IsLocal bool
OracleKey []byte OracleKey []byte
OracleData []byte OracleData []byte
OracleOffset uint32
}
// GetType returns the type for the preimage oracle data.
func (p *PreimageOracleData) GetType() *big.Int {
return big.NewInt(int64(p.OracleKey[0]))
} }
// GetIdent returns the ident for the preimage oracle data. // GetIdent returns the ident for the preimage oracle data.
func (p *PreimageOracleData) GetIdent() *big.Int { func (p *PreimageOracleData) GetIdent() *big.Int {
return big.NewInt(int64(p.OracleData[0])) return big.NewInt(0).SetBytes(p.OracleKey[1:])
}
// GetPreimageWithoutSize returns the preimage for the preimage oracle data.
func (p *PreimageOracleData) GetPreimageWithoutSize() []byte {
return p.OracleData[8:]
} }
// NewPreimageOracleData creates a new [PreimageOracleData] instance. // NewPreimageOracleData creates a new [PreimageOracleData] instance.
func NewPreimageOracleData(key []byte, data []byte) PreimageOracleData { func NewPreimageOracleData(key []byte, data []byte, offset uint32) PreimageOracleData {
return PreimageOracleData{ return PreimageOracleData{
IsLocal: len(key) > 0 && key[0] == byte(1), IsLocal: len(key) > 0 && key[0] == byte(1),
OracleKey: key, OracleKey: key,
OracleData: data, OracleData: data,
OracleOffset: offset,
} }
} }
......
...@@ -8,16 +8,18 @@ import ( ...@@ -8,16 +8,18 @@ import (
func TestNewPreimageOracleData(t *testing.T) { func TestNewPreimageOracleData(t *testing.T) {
t.Run("LocalData", func(t *testing.T) { t.Run("LocalData", func(t *testing.T) {
data := NewPreimageOracleData([]byte{1, 2, 3}, []byte{4, 5, 6}) data := NewPreimageOracleData([]byte{1, 2, 3}, []byte{4, 5, 6}, 7)
require.True(t, data.IsLocal) require.True(t, data.IsLocal)
require.Equal(t, []byte{1, 2, 3}, data.OracleKey) require.Equal(t, []byte{1, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.OracleData)
require.Equal(t, uint32(7), data.OracleOffset)
}) })
t.Run("GlobalData", func(t *testing.T) { t.Run("GlobalData", func(t *testing.T) {
data := NewPreimageOracleData([]byte{0, 2, 3}, []byte{4, 5, 6}) data := NewPreimageOracleData([]byte{0, 2, 3}, []byte{4, 5, 6}, 7)
require.False(t, data.IsLocal) require.False(t, data.IsLocal)
require.Equal(t, []byte{0, 2, 3}, data.OracleKey) require.Equal(t, []byte{0, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.OracleData)
require.Equal(t, uint32(7), data.OracleOffset)
}) })
} }
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