Commit 71c1b929 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into dependabot/npm_and_yarn/nrwl/nx-cloud-16.3.0

parents 56e29726 9c92d049
......@@ -22,6 +22,8 @@ type BlockHeader struct {
ParentHash common.Hash `gorm:"serializer:json"`
Number U256
Timestamp uint64
GethHeader *GethHeader `gorm:"serializer:rlp;column:rlp_bytes"`
}
func BlockHeaderFromGethHeader(header *types.Header) BlockHeader {
......@@ -30,6 +32,8 @@ func BlockHeaderFromGethHeader(header *types.Header) BlockHeader {
ParentHash: header.ParentHash,
Number: U256{Int: header.Number},
Timestamp: header.Time,
GethHeader: (*GethHeader)(header),
}
}
......
......@@ -16,26 +16,37 @@ import (
*/
type ContractEvent struct {
GUID uuid.UUID `gorm:"primaryKey"`
BlockHash common.Hash `gorm:"serializer:json"`
TransactionHash common.Hash `gorm:"serializer:json"`
GUID uuid.UUID `gorm:"primaryKey"`
BlockHash common.Hash `gorm:"serializer:json"`
ContractAddress common.Address `gorm:"serializer:json"`
TransactionHash common.Hash `gorm:"serializer:json"`
EventSignature common.Hash `gorm:"serializer:json"`
LogIndex uint64
Timestamp uint64
GethLog *types.Log `gorm:"serializer:rlp;column:rlp_bytes"`
}
func ContractEventFromGethLog(log *types.Log, timestamp uint64) ContractEvent {
eventSig := common.Hash{}
if len(log.Topics) > 0 {
eventSig = log.Topics[0]
}
return ContractEvent{
GUID: uuid.New(),
BlockHash: log.BlockHash,
ContractAddress: log.Address,
TransactionHash: log.TxHash,
EventSignature: log.Topics[0],
EventSignature: eventSig,
LogIndex: uint64(log.Index),
Timestamp: timestamp,
GethLog: log,
}
}
......
package database
import (
"context"
"fmt"
"reflect"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
"gorm.io/gorm/schema"
)
type RLPSerializer struct{}
type RLPInterface interface {
rlp.Encoder
rlp.Decoder
}
func init() {
schema.RegisterSerializer("rlp", RLPSerializer{})
}
func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error {
fieldValue := reflect.New(field.FieldType)
if dbValue != nil {
var bytes []byte
switch v := dbValue.(type) {
case []byte:
bytes = v
case string:
b, err := hexutil.Decode(v)
if err != nil {
return err
}
bytes = b
default:
return fmt.Errorf("unrecognized RLP bytes: %#v", dbValue)
}
if len(bytes) > 0 {
err := rlp.DecodeBytes(bytes, fieldValue.Interface())
if err != nil {
return err
}
}
}
field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
return nil
}
func (RLPSerializer) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
// Even though rlp.Encode takes an interface and will error out if the passed interface does not
// satisfy the interface, we check here since we also want to make sure this type satisfies the
// rlp.Decoder interface as well
i := reflect.TypeOf(new(RLPInterface)).Elem()
if !reflect.TypeOf(fieldValue).Implements(i) {
return nil, fmt.Errorf("%T does not satisfy RLP Encoder & Decoder interface", fieldValue)
}
rlpBytes, err := rlp.EncodeToBytes(fieldValue)
if err != nil {
return nil, err
}
return hexutil.Bytes(rlpBytes).MarshalText()
}
......@@ -3,8 +3,12 @@ package database
import (
"database/sql/driver"
"errors"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/jackc/pgtype"
)
......@@ -13,7 +17,7 @@ var big10 = big.NewInt(10)
var ErrU256Overflow = errors.New("number exceeds u256")
var ErrU256ContainsDecimal = errors.New("number contains fractional digits")
var ErrU256NotNull = errors.New("number cannot be null")
var ErrU256Null = errors.New("number cannot be null")
// U256 is a wrapper over big.Int that conforms to the database U256 numeric domain type
type U256 struct {
......@@ -30,7 +34,7 @@ func (u256 *U256) Scan(src interface{}) error {
} else if numeric.Exp < 0 {
return ErrU256ContainsDecimal
} else if numeric.Status == pgtype.Null {
return ErrU256NotNull
return ErrU256Null
}
// factor in the powers of 10
......@@ -54,7 +58,7 @@ func (u256 *U256) Scan(src interface{}) error {
func (u256 U256) Value() (driver.Value, error) {
// check bounds
if u256.Int == nil {
return nil, ErrU256NotNull
return nil, ErrU256Null
} else if u256.Int.Cmp(u256BigIntOverflow) >= 0 {
return nil, ErrU256Overflow
}
......@@ -63,3 +67,29 @@ func (u256 U256) Value() (driver.Value, error) {
numeric := pgtype.Numeric{Int: u256.Int, Status: pgtype.Present}
return numeric.Value()
}
type GethHeader types.Header
func (h *GethHeader) EncodeRLP(w io.Writer) error {
return types.NewBlockWithHeader((*types.Header)(h)).EncodeRLP(w)
}
func (h *GethHeader) DecodeRLP(s *rlp.Stream) error {
block := new(types.Block)
err := block.DecodeRLP(s)
if err != nil {
return err
}
header := block.Header()
*h = (GethHeader)(*header)
return nil
}
func (h *GethHeader) Header() *types.Header {
return (*types.Header)(h)
}
func (h *GethHeader) Hash() common.Hash {
return h.Header().Hash()
}
......@@ -16,6 +16,7 @@ import (
"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/rlp"
"github.com/stretchr/testify/require"
)
......@@ -62,6 +63,9 @@ func TestE2EBlockHeaders(t *testing.T) {
require.Equal(t, header.Hash(), indexedHeader.Hash)
require.Equal(t, header.ParentHash, indexedHeader.ParentHash)
require.Equal(t, header.Time, indexedHeader.Timestamp)
// ensure the right rlp encoding is stored. checking the hashes sufficies
require.Equal(t, header.Hash(), indexedHeader.GethHeader.Hash())
}
})
......@@ -116,9 +120,17 @@ func TestE2EBlockHeaders(t *testing.T) {
require.NoError(t, err)
require.Equal(t, log.Topics[0], contractEvent.EventSignature)
require.Equal(t, log.BlockHash, contractEvent.BlockHash)
require.Equal(t, log.Address, contractEvent.ContractAddress)
require.Equal(t, log.TxHash, contractEvent.TransactionHash)
require.Equal(t, log.Index, uint(contractEvent.LogIndex))
// ensure the right rlp encoding of the contract log is stored
logRlp, err := rlp.EncodeToBytes(&log)
require.NoError(t, err)
contractEventRlp, err := rlp.EncodeToBytes(contractEvent.GethLog)
require.NoError(t, err)
require.ElementsMatch(t, logRlp, contractEventRlp)
// ensure the block is also indexed
block, err := testSuite.L1Client.BlockByNumber(testCtx, big.NewInt(int64(log.BlockNumber)))
require.NoError(t, err)
......@@ -131,6 +143,10 @@ func TestE2EBlockHeaders(t *testing.T) {
require.Equal(t, block.ParentHash(), l1BlockHeader.ParentHash)
require.Equal(t, block.Number(), l1BlockHeader.Number.Int)
require.Equal(t, block.Time(), l1BlockHeader.Timestamp)
// ensure the right rlp encoding is stored. checking the hashes
// suffices as it is based on the rlp bytes of the header
require.Equal(t, block.Hash(), l1BlockHeader.GethHeader.Hash())
}
})
}
......@@ -7,18 +7,25 @@ CREATE DOMAIN UINT256 AS NUMERIC
*/
CREATE TABLE IF NOT EXISTS l1_block_headers (
-- Searchable fields
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number UINT256 NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
timestamp INTEGER NOT NULL CHECK (timestamp > 0),
-- Raw Data
rlp_bytes VARCHAR NOT NULL
);
CREATE TABLE IF NOT EXISTS l2_block_headers (
-- Block header
-- Searchable fields
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number UINT256 NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
timestamp INTEGER NOT NULL CHECK (timestamp > 0),
-- Raw Data
rlp_bytes VARCHAR NOT NULL
);
/**
......@@ -26,21 +33,31 @@ CREATE TABLE IF NOT EXISTS l2_block_headers (
*/
CREATE TABLE IF NOT EXISTS l1_contract_events (
-- Searchable fields
guid VARCHAR NOT NULL PRIMARY KEY,
block_hash VARCHAR NOT NULL REFERENCES l1_block_headers(hash),
contract_address VARCHAR NOT NULL,
transaction_hash VARCHAR NOT NULL,
event_signature VARCHAR NOT NULL,
log_index INTEGER NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
event_signature VARCHAR NOT NULL, -- bytes32(0x0) when topics are missing
timestamp INTEGER NOT NULL CHECK (timestamp > 0),
-- Raw Data
rlp_bytes VARCHAR NOT NULL
);
CREATE TABLE IF NOT EXISTS l2_contract_events (
-- Searchable fields
guid VARCHAR NOT NULL PRIMARY KEY,
block_hash VARCHAR NOT NULL REFERENCES l2_block_headers(hash),
contract_address VARCHAR NOT NULL,
transaction_hash VARCHAR NOT NULL,
event_signature VARCHAR NOT NULL,
log_index INTEGER NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
event_signature VARCHAR NOT NULL, -- bytes32(0x0) when topics are missing
timestamp INTEGER NOT NULL CHECK (timestamp > 0),
-- Raw Data
rlp_bytes VARCHAR NOT NULL
);
-- Tables that index finalization markers for L2 blocks.
......
......@@ -9,20 +9,17 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/google/uuid"
)
type ProcessedContractEventLogIndexKey struct {
header common.Hash
index uint
blockHash common.Hash
index uint
}
type ProcessedContractEvents struct {
events []*database.ContractEvent
eventsBySignature map[common.Hash][]*database.ContractEvent
eventByLogIndex map[ProcessedContractEventLogIndexKey]*database.ContractEvent
eventLog map[uuid.UUID]*types.Log
}
func NewProcessedContractEvents() *ProcessedContractEvents {
......@@ -30,17 +27,18 @@ func NewProcessedContractEvents() *ProcessedContractEvents {
events: []*database.ContractEvent{},
eventsBySignature: make(map[common.Hash][]*database.ContractEvent),
eventByLogIndex: make(map[ProcessedContractEventLogIndexKey]*database.ContractEvent),
eventLog: make(map[uuid.UUID]*types.Log),
}
}
func (p *ProcessedContractEvents) AddLog(log *types.Log, time uint64) *database.ContractEvent {
contractEvent := database.ContractEventFromGethLog(log, time)
emptyHash := common.Hash{}
p.events = append(p.events, &contractEvent)
p.eventsBySignature[contractEvent.EventSignature] = append(p.eventsBySignature[contractEvent.EventSignature], &contractEvent)
p.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index}] = &contractEvent
p.eventLog[contractEvent.GUID] = log
if contractEvent.EventSignature != emptyHash { // ignore anon events
p.eventsBySignature[contractEvent.EventSignature] = append(p.eventsBySignature[contractEvent.EventSignature], &contractEvent)
}
return &contractEvent
}
......
......@@ -49,7 +49,7 @@ type CrossDomainMessengerRelayedMessageEvent struct {
}
func CrossDomainMessengerSentMessageEvents(events *ProcessedContractEvents) ([]CrossDomainMessengerSentMessageEvent, error) {
crossDomainMessengerABI, err := bindings.L1CrossDomainMessengerMetaData.GetAbi()
crossDomainMessengerABI, err := bindings.CrossDomainMessengerMetaData.GetAbi()
if err != nil {
return nil, err
}
......@@ -60,16 +60,18 @@ func CrossDomainMessengerSentMessageEvents(events *ProcessedContractEvents) ([]C
processedSentMessageEvents := events.eventsBySignature[sentMessageEventAbi.ID]
crossDomainMessageEvents := make([]CrossDomainMessengerSentMessageEvent, len(processedSentMessageEvents))
for i, sentMessageEvent := range processedSentMessageEvents {
log := events.eventLog[sentMessageEvent.GUID]
log := sentMessageEvent.GethLog
var sentMsgData bindings.CrossDomainMessengerSentMessage
sentMsgData.Raw = *log
err = UnpackLog(&sentMsgData, log, sentMessageEventAbi.Name, crossDomainMessengerABI)
if err != nil {
return nil, err
}
var sentMsgExtensionData bindings.CrossDomainMessengerSentMessageExtension1
extensionLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GUID]
extensionLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GethLog
sentMsgExtensionData.Raw = *extensionLog
err = UnpackLog(&sentMsgExtensionData, extensionLog, sentMessageEventExtensionAbi.Name, crossDomainMessengerABI)
if err != nil {
return nil, err
......@@ -101,15 +103,19 @@ func CrossDomainMessengerRelayedMessageEvents(events *ProcessedContractEvents) (
processedRelayedMessageEvents := events.eventsBySignature[relayedMessageEventAbi.ID]
crossDomainMessageEvents := make([]CrossDomainMessengerRelayedMessageEvent, len(processedRelayedMessageEvents))
for i, relayedMessageEvent := range processedRelayedMessageEvents {
log := events.eventLog[relayedMessageEvent.GUID]
log := relayedMessageEvent.GethLog
var relayedMsgData bindings.CrossDomainMessengerRelayedMessage
relayedMsgData.Raw = *log
err = UnpackLog(&relayedMsgData, log, relayedMessageEventAbi.Name, crossDomainMessengerABI)
if err != nil {
return nil, err
}
crossDomainMessageEvents[i] = CrossDomainMessengerRelayedMessageEvent{&relayedMsgData, relayedMessageEvent}
crossDomainMessageEvents[i] = CrossDomainMessengerRelayedMessageEvent{
CrossDomainMessengerRelayedMessage: &relayedMsgData,
RawEvent: relayedMessageEvent,
}
}
return crossDomainMessageEvents, nil
......
......@@ -399,10 +399,10 @@ func l1ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
sentMessages := make([]*database.L1BridgeMessage, len(sentMessageEvents))
for i, sentMessageEvent := range sentMessageEvents {
log := events.eventLog[sentMessageEvent.RawEvent.GUID]
log := sentMessageEvent.RawEvent.GethLog
// extract the deposit hash from the previous TransactionDepositedEvent
transactionDepositedLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index - 1}].GUID]
transactionDepositedLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index - 1}].GethLog
depositTx, err := derive.UnmarshalDepositLogEvent(transactionDepositedLog)
if err != nil {
return err
......@@ -479,10 +479,10 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
deposits := make([]*database.L1BridgeDeposit, len(initiatedDepositEvents))
for i, initiatedBridgeEvent := range initiatedDepositEvents {
log := events.eventLog[initiatedBridgeEvent.RawEvent.GUID]
log := initiatedBridgeEvent.RawEvent.GethLog
// extract the deposit hash from the following TransactionDeposited event
transactionDepositedLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GUID]
transactionDepositedLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GethLog
depositTx, err := derive.UnmarshalDepositLogEvent(transactionDepositedLog)
if err != nil {
return err
......
......@@ -106,17 +106,8 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
l2Headers := make([]*database.L2BlockHeader, len(headers))
l2HeaderMap := make(map[common.Hash]*types.Header)
for i, header := range headers {
blockHash := header.Hash()
l2Headers[i] = &database.L2BlockHeader{
BlockHeader: database.BlockHeader{
Hash: blockHash,
ParentHash: header.ParentHash,
Number: database.U256{Int: header.Number},
Timestamp: header.Time,
},
}
l2HeaderMap[blockHash] = header
l2Headers[i] = &database.L2BlockHeader{BlockHeader: database.BlockHeaderFromGethHeader(header)}
l2HeaderMap[l2Headers[i].Hash] = header
}
/** Watch for Contract Events **/
......@@ -255,10 +246,10 @@ func l2ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
sentMessages := make([]*database.L2BridgeMessage, len(sentMessageEvents))
for i, sentMessageEvent := range sentMessageEvents {
log := events.eventLog[sentMessageEvent.RawEvent.GUID]
log := sentMessageEvent.RawEvent.GethLog
// extract the withdrawal hash from the previous MessagePassed event
msgPassedLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index - 1}].GUID]
msgPassedLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index - 1}].GethLog
msgPassedEvent, err := l2ToL1MessagePasserABI.ParseMessagePassed(*msgPassedLog)
if err != nil {
return err
......@@ -355,10 +346,10 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
withdrawals := make([]*database.L2BridgeWithdrawal, len(initiatedWithdrawalEvents))
for i, initiatedBridgeEvent := range initiatedWithdrawalEvents {
log := events.eventLog[initiatedBridgeEvent.RawEvent.GUID]
log := initiatedBridgeEvent.RawEvent.GethLog
// extract the withdrawal hash from the following MessagePassed event
msgPassedLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GUID]
msgPassedLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GethLog
msgPassedEvent, err := l2ToL1MessagePasserABI.ParseMessagePassed(*msgPassedLog)
if err != nil {
return err
......
......@@ -20,15 +20,19 @@ func L2ToL1MessagePasserMessagesPassed(events *ProcessedContractEvents) ([]L2ToL
processedMessagePassedEvents := events.eventsBySignature[l2ToL1MessagePasserAbi.Events[eventName].ID]
messagesPassed := make([]L2ToL1MessagePasserMessagePassed, len(processedMessagePassedEvents))
for i, messagePassedEvent := range processedMessagePassedEvents {
log := events.eventLog[messagePassedEvent.GUID]
log := messagePassedEvent.GethLog
var messagePassed bindings.L2ToL1MessagePasserMessagePassed
messagePassed.Raw = *log
err := UnpackLog(&messagePassed, log, eventName, l2ToL1MessagePasserAbi)
if err != nil {
return nil, err
}
messagesPassed[i] = L2ToL1MessagePasserMessagePassed{&messagePassed, messagePassedEvent}
messagesPassed[i] = L2ToL1MessagePasserMessagePassed{
L2ToL1MessagePasserMessagePassed: &messagePassed,
RawEvent: messagePassedEvent,
}
}
return messagesPassed, nil
......
package processor
import (
"context"
"errors"
"math/big"
......@@ -9,10 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
type OptimismPortalTransactionDepositEvent struct {
......@@ -51,7 +47,7 @@ func OptimismPortalTransactionDepositEvents(events *ProcessedContractEvents) ([]
processedTxDepositedEvents := events.eventsBySignature[derive.DepositEventABIHash]
txDeposits := make([]OptimismPortalTransactionDepositEvent, len(processedTxDepositedEvents))
for i, txDepositEvent := range processedTxDepositedEvents {
log := events.eventLog[txDepositEvent.GUID]
log := txDepositEvent.GethLog
depositTx, err := derive.UnmarshalDepositLogEvent(log)
if err != nil {
......@@ -59,12 +55,17 @@ func OptimismPortalTransactionDepositEvents(events *ProcessedContractEvents) ([]
}
var txDeposit bindings.OptimismPortalTransactionDeposited
txDeposit.Raw = *log
err = UnpackLog(&txDeposit, log, eventName, optimismPortalAbi)
if err != nil {
return nil, err
}
txDeposits[i] = OptimismPortalTransactionDepositEvent{&txDeposit, depositTx, txDepositEvent}
txDeposits[i] = OptimismPortalTransactionDepositEvent{
OptimismPortalTransactionDeposited: &txDeposit,
DepositTx: depositTx,
RawEvent: txDepositEvent,
}
}
return txDeposits, nil
......@@ -80,15 +81,19 @@ func OptimismPortalWithdrawalProvenEvents(events *ProcessedContractEvents) ([]Op
processedWithdrawalProvenEvents := events.eventsBySignature[optimismPortalAbi.Events[eventName].ID]
provenEvents := make([]OptimismPortalWithdrawalProvenEvent, len(processedWithdrawalProvenEvents))
for i, provenEvent := range processedWithdrawalProvenEvents {
log := events.eventLog[provenEvent.GUID]
log := provenEvent.GethLog
var withdrawalProven bindings.OptimismPortalWithdrawalProven
withdrawalProven.Raw = *log
err := UnpackLog(&withdrawalProven, log, eventName, optimismPortalAbi)
if err != nil {
return nil, err
}
provenEvents[i] = OptimismPortalWithdrawalProvenEvent{&withdrawalProven, provenEvent}
provenEvents[i] = OptimismPortalWithdrawalProvenEvent{
OptimismPortalWithdrawalProven: &withdrawalProven,
RawEvent: provenEvent,
}
}
return provenEvents, nil
......@@ -104,7 +109,7 @@ func OptimismPortalWithdrawalFinalizedEvents(events *ProcessedContractEvents) ([
processedWithdrawalFinalizedEvents := events.eventsBySignature[optimismPortalAbi.Events[eventName].ID]
finalizedEvents := make([]OptimismPortalWithdrawalFinalizedEvent, len(processedWithdrawalFinalizedEvents))
for i, finalizedEvent := range processedWithdrawalFinalizedEvents {
log := events.eventLog[finalizedEvent.GUID]
log := finalizedEvent.GethLog
var withdrawalFinalized bindings.OptimismPortalWithdrawalFinalized
err := UnpackLog(&withdrawalFinalized, log, eventName, optimismPortalAbi)
......@@ -112,36 +117,11 @@ func OptimismPortalWithdrawalFinalizedEvents(events *ProcessedContractEvents) ([
return nil, err
}
finalizedEvents[i] = OptimismPortalWithdrawalFinalizedEvent{&withdrawalFinalized, finalizedEvent}
finalizedEvents[i] = OptimismPortalWithdrawalFinalizedEvent{
OptimismPortalWithdrawalFinalized: &withdrawalFinalized,
RawEvent: finalizedEvent,
}
}
return finalizedEvents, nil
}
func OptimismPortalQueryProvenWithdrawal(ethClient *ethclient.Client, portalAddress common.Address, withdrawalHash common.Hash) (OptimismPortalProvenWithdrawal, error) {
var provenWithdrawal OptimismPortalProvenWithdrawal
optimismPortalAbi, err := bindings.OptimismPortalMetaData.GetAbi()
if err != nil {
return provenWithdrawal, err
}
name := "provenWithdrawals"
txData, err := optimismPortalAbi.Pack(name, withdrawalHash)
if err != nil {
return provenWithdrawal, err
}
callMsg := ethereum.CallMsg{To: &portalAddress, Data: txData}
data, err := ethClient.CallContract(context.Background(), callMsg, nil)
if err != nil {
return provenWithdrawal, err
}
err = optimismPortalAbi.UnpackIntoInterface(&provenWithdrawal, name, data)
if err != nil {
return provenWithdrawal, err
}
return provenWithdrawal, nil
}
......@@ -97,7 +97,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
processedInitiatedBridgeEvents := events.eventsBySignature[StandardBridgeABI.Events[eventName].ID]
initiatedBridgeEvents := make([]StandardBridgeInitiatedEvent, len(processedInitiatedBridgeEvents))
for i, bridgeInitiatedEvent := range processedInitiatedBridgeEvents {
log := events.eventLog[bridgeInitiatedEvent.GUID]
log := bridgeInitiatedEvent.GethLog
var bridgeData BridgeEvent
err := UnpackLog(&bridgeData, log, eventName, StandardBridgeABI)
......@@ -109,7 +109,8 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
// - L1: BridgeInitiated -> Portal#DepositTransaction -> SentMessage ...
// - L1: BridgeInitiated -> L2ToL1MessagePasser#MessagePassed -> SentMessage ...
var sentMsgData bindings.L1CrossDomainMessengerSentMessage
sentMsgLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 2}].GUID]
sentMsgLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 2}].GethLog
sentMsgData.Raw = *sentMsgLog
err = UnpackLog(&sentMsgData, sentMsgLog, sentMessageEventAbi.Name, l1CrossDomainMessengerABI)
if err != nil {
return nil, err
......@@ -127,6 +128,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
// represent eth bridge as an erc20
erc20BridgeData = &bindings.StandardBridgeERC20BridgeInitiated{
Raw: *log,
// Represent ETH using the hardcoded address
LocalToken: predeploys.LegacyERC20ETHAddr, RemoteToken: predeploys.LegacyERC20ETHAddr,
// Bridge data
......@@ -136,6 +138,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
case bindings.StandardBridgeERC20BridgeInitiated:
_temp := any(bridgeData).(bindings.StandardBridgeERC20BridgeInitiated)
erc20BridgeData = &_temp
erc20BridgeData.Raw = *log
expectedCrossDomainMessage, err = StandardBridgeABI.Pack(finalizeMethodName, erc20BridgeData.RemoteToken, erc20BridgeData.LocalToken, erc20BridgeData.From, erc20BridgeData.To, erc20BridgeData.Amount, erc20BridgeData.ExtraData)
if err != nil {
return nil, err
......@@ -146,7 +149,11 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
return nil, errors.New("bridge cross domain message mismatch")
}
initiatedBridgeEvents[i] = StandardBridgeInitiatedEvent{erc20BridgeData, sentMsgData.MessageNonce, bridgeInitiatedEvent}
initiatedBridgeEvents[i] = StandardBridgeInitiatedEvent{
StandardBridgeERC20BridgeInitiated: erc20BridgeData,
CrossDomainMessengerNonce: sentMsgData.MessageNonce,
RawEvent: bridgeInitiatedEvent,
}
}
return initiatedBridgeEvents, nil
......@@ -190,7 +197,7 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
processedFinalizedBridgeEvents := events.eventsBySignature[StandardBridgeABI.Events[eventName].ID]
finalizedBridgeEvents := make([]StandardBridgeFinalizedEvent, len(processedFinalizedBridgeEvents))
for i, bridgeFinalizedEvent := range processedFinalizedBridgeEvents {
log := events.eventLog[bridgeFinalizedEvent.GUID]
log := bridgeFinalizedEvent.GethLog
var bridgeData BridgeEvent
err := UnpackLog(&bridgeData, log, eventName, StandardBridgeABI)
......@@ -199,7 +206,7 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
}
// Look for the RelayedMessage event that follows right after the BridgeFinalized Event
relayedMsgLog := events.eventLog[events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GUID]
relayedMsgLog := events.eventByLogIndex[ProcessedContractEventLogIndexKey{log.BlockHash, log.Index + 1}].GethLog
if relayedMsgLog.Topics[0] != relayedMessageEventAbi.ID {
return nil, errors.New("unexpected bridge event ordering")
}
......@@ -257,6 +264,7 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
case bindings.StandardBridgeETHBridgeFinalized:
ethBridgeData := any(bridgeData).(bindings.StandardBridgeETHBridgeFinalized)
erc20BridgeData = &bindings.StandardBridgeERC20BridgeFinalized{
Raw: *log,
// Represent ETH using the hardcoded address
LocalToken: predeploys.LegacyERC20ETHAddr, RemoteToken: predeploys.LegacyERC20ETHAddr,
// Bridge data
......@@ -266,9 +274,14 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
case bindings.StandardBridgeERC20BridgeFinalized:
_temp := any(bridgeData).(bindings.StandardBridgeERC20BridgeFinalized)
erc20BridgeData = &_temp
erc20BridgeData.Raw = *log
}
finalizedBridgeEvents[i] = StandardBridgeFinalizedEvent{erc20BridgeData, nonce, bridgeFinalizedEvent}
finalizedBridgeEvents[i] = StandardBridgeFinalizedEvent{
StandardBridgeERC20BridgeFinalized: erc20BridgeData,
CrossDomainMessengerNonce: nonce,
RawEvent: bridgeFinalizedEvent,
}
}
return finalizedBridgeEvents, nil
......
......@@ -297,7 +297,78 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
MIPS_Test:test_step_abi_succeeds() (gas: 57803)
MIPS_Test:test_add_succeeds() (gas: 121593)
MIPS_Test:test_addi_succeeds() (gas: 121896)
MIPS_Test:test_addu_succeeds() (gas: 121645)
MIPS_Test:test_addui_succeeds() (gas: 121953)
MIPS_Test:test_and_succeeds() (gas: 121628)
MIPS_Test:test_andi_succeeds() (gas: 121770)
MIPS_Test:test_beq_succeeds() (gas: 202355)
MIPS_Test:test_bgez_succeeds() (gas: 121507)
MIPS_Test:test_bgtz_succeeds() (gas: 121428)
MIPS_Test:test_blez_succeeds() (gas: 121406)
MIPS_Test:test_bltz_succeeds() (gas: 121482)
MIPS_Test:test_bne_succeeds() (gas: 121548)
MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85977)
MIPS_Test:test_brk_succeeds() (gas: 121509)
MIPS_Test:test_clo_succeeds() (gas: 121991)
MIPS_Test:test_clone_succeeds() (gas: 121484)
MIPS_Test:test_clz_succeeds() (gas: 122440)
MIPS_Test:test_div_succeeds() (gas: 121806)
MIPS_Test:test_divu_succeeds() (gas: 121806)
MIPS_Test:test_exit_succeeds() (gas: 121386)
MIPS_Test:test_fcntl_succeeds() (gas: 203171)
MIPS_Test:test_illegal_instruction_fails() (gas: 91153)
MIPS_Test:test_invalid_root_fails() (gas: 435656)
MIPS_Test:test_jal_succeeds() (gas: 117399)
MIPS_Test:test_jalr_succeeds() (gas: 121349)
MIPS_Test:test_jr_succeeds() (gas: 121138)
MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85512)
MIPS_Test:test_jump_succeeds() (gas: 120353)
MIPS_Test:test_lb_succeeds() (gas: 127346)
MIPS_Test:test_lbu_succeeds() (gas: 127266)
MIPS_Test:test_lh_succeeds() (gas: 127345)
MIPS_Test:test_lhu_succeeds() (gas: 127262)
MIPS_Test:test_ll_succeeds() (gas: 127282)
MIPS_Test:test_lui_succeeds() (gas: 121531)
MIPS_Test:test_lw_succeeds() (gas: 127158)
MIPS_Test:test_lwl_succeeds() (gas: 241457)
MIPS_Test:test_lwr_succeeds() (gas: 241767)
MIPS_Test:test_mfhi_succeeds() (gas: 121458)
MIPS_Test:test_mflo_succeeds() (gas: 121484)
MIPS_Test:test_mmap_succeeds() (gas: 118492)
MIPS_Test:test_movn_succeeds() (gas: 202409)
MIPS_Test:test_movz_succeeds() (gas: 202313)
MIPS_Test:test_mthi_succeeds() (gas: 121428)
MIPS_Test:test_mtlo_succeeds() (gas: 121478)
MIPS_Test:test_mul_succeeds() (gas: 121541)
MIPS_Test:test_mult_succeeds() (gas: 121645)
MIPS_Test:test_multu_succeeds() (gas: 121698)
MIPS_Test:test_nor_succeeds() (gas: 121739)
MIPS_Test:test_or_succeeds() (gas: 121635)
MIPS_Test:test_ori_succeeds() (gas: 121865)
MIPS_Test:test_preimage_read_succeeds() (gas: 235922)
MIPS_Test:test_preimage_write_succeeds() (gas: 126473)
MIPS_Test:test_prestate_exited_succeeds() (gas: 112970)
MIPS_Test:test_sb_succeeds() (gas: 159993)
MIPS_Test:test_sc_succeeds() (gas: 160187)
MIPS_Test:test_sh_succeeds() (gas: 160096)
MIPS_Test:test_sll_succeeds() (gas: 121434)
MIPS_Test:test_sllv_succeeds() (gas: 121624)
MIPS_Test:test_slt_succeeds() (gas: 203244)
MIPS_Test:test_sltu_succeeds() (gas: 121871)
MIPS_Test:test_sra_succeeds() (gas: 121719)
MIPS_Test:test_srav_succeeds() (gas: 121959)
MIPS_Test:test_srl_succeeds() (gas: 121514)
MIPS_Test:test_srlv_succeeds() (gas: 121707)
MIPS_Test:test_step_abi_succeeds() (gas: 57871)
MIPS_Test:test_sub_succeeds() (gas: 121674)
MIPS_Test:test_subu_succeeds() (gas: 121682)
MIPS_Test:test_sw_succeeds() (gas: 160050)
MIPS_Test:test_swl_succeeds() (gas: 160066)
MIPS_Test:test_swr_succeeds() (gas: 160141)
MIPS_Test:test_xor_succeeds() (gas: 121685)
MIPS_Test:test_xori_succeeds() (gas: 121894)
MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733)
MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889)
MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845)
......@@ -360,9 +431,9 @@ OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_ifOutp
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_ifOutputTimestampIsNotFinalized_reverts() (gas: 182306)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_ifWithdrawalNotProven_reverts() (gas: 41780)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_ifWithdrawalProofNotOldEnough_reverts() (gas: 173953)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onInsufficientGas_reverts() (gas: 180701)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onInsufficientGas_reverts() (gas: 180724)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onRecentWithdrawal_reverts() (gas: 154740)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onReentrancy_reverts() (gas: 218747)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onReentrancy_reverts() (gas: 218770)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_onReplay_reverts() (gas: 220983)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_paused_reverts() (gas: 38706)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_provenWithdrawalHash_succeeds() (gas: 209679)
......
......@@ -5,7 +5,9 @@ import (
"fmt"
"math/big"
"os"
"strconv"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/accounts/abi"
......@@ -60,6 +62,15 @@ var (
proveWithdrawalInputsArgs = abi.Arguments{
{Name: "inputs", Type: proveWithdrawalInputs},
}
// cannonMemoryProof inputs tuple (bytes32, bytes)
cannonMemoryProof, _ = abi.NewType("tuple", "CannonMemoryProof", []abi.ArgumentMarshaling{
{Name: "memRoot", Type: "bytes32"},
{Name: "proof", Type: "bytes"},
})
cannonMemoryProofArgs = abi.Arguments{
{Name: "encodedCannonMemoryProof", Type: cannonMemoryProof},
}
)
func main() {
......@@ -312,6 +323,39 @@ func main() {
// Print the output
fmt.Print(hexutil.Encode(packed[32:]))
case "cannonMemoryProof":
// <pc, insn, [memAddr, memValue]>
mem := mipsevm.NewMemory()
if len(args) != 3 && len(args) != 5 {
panic("Error: cannonMemoryProofWithProof requires 2 or 4 arguments")
}
pc, err := strconv.ParseUint(args[1], 10, 32)
checkErr(err, "Error decocding addr")
insn, err := strconv.ParseUint(args[2], 10, 32)
checkErr(err, "Error decocding insn")
mem.SetMemory(uint32(pc), uint32(insn))
var insnProof, memProof [896]byte
if len(args) == 5 {
memAddr, err := strconv.ParseUint(args[3], 10, 32)
checkErr(err, "Error decocding memAddr")
memValue, err := strconv.ParseUint(args[4], 10, 32)
checkErr(err, "Error decocding memValue")
mem.SetMemory(uint32(memAddr), uint32(memValue))
memProof = mem.MerkleProof(uint32(memAddr))
}
insnProof = mem.MerkleProof(uint32(pc))
output := struct {
MemRoot common.Hash
Proof []byte
}{
MemRoot: mem.MerkleRoot(),
Proof: append(insnProof[:], memProof[:]...),
}
packed, err := cannonMemoryProofArgs.Pack(&output)
checkErr(err, "Error encoding output")
fmt.Print(hexutil.Encode(packed[32:]))
default:
panic(fmt.Errorf("Unknown command: %s", args[0]))
}
......
......@@ -678,6 +678,38 @@ contract FFIInterface is Test {
return abi.decode(vm.ffi(cmds), (bytes32, bytes, bytes, bytes[]));
}
function getCannonMemoryProof(uint32 pc, uint32 insn) external returns (bytes32, bytes memory) {
string[] memory cmds = new string[](4);
cmds[0] = "scripts/differential-testing/differential-testing";
cmds[1] = "cannonMemoryProof";
cmds[2] = vm.toString(pc);
cmds[3] = vm.toString(insn);
bytes memory result = vm.ffi(cmds);
(bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes));
return (memRoot, proof);
}
function getCannonMemoryProof(
uint32 pc,
uint32 insn,
uint32 memAddr,
uint32 memVal
)
external
returns (bytes32, bytes memory)
{
string[] memory cmds = new string[](6);
cmds[0] = "scripts/differential-testing/differential-testing";
cmds[1] = "cannonMemoryProof";
cmds[2] = vm.toString(pc);
cmds[3] = vm.toString(insn);
cmds[4] = vm.toString(memAddr);
cmds[5] = vm.toString(memVal);
bytes memory result = vm.ffi(cmds);
(bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes));
return (memRoot, proof);
}
}
// Used for testing a future upgrade beyond the current implementations.
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { CommonTest } from "./CommonTest.t.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
contract MIPS_Test is Test {
contract MIPS_Test is CommonTest {
MIPS internal mips;
PreimageOracle internal oracle;
function setUp() public {
function setUp() public virtual override {
super.setUp();
oracle = new PreimageOracle();
mips = new MIPS(oracle);
vm.store(address(mips), 0x0, bytes32(abi.encode(address(oracle))));
......@@ -41,6 +42,1448 @@ contract MIPS_Test is Test {
assertTrue(postState != bytes32(0));
}
function test_add_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x20); // add t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 12;
state.registers[18] = 20;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_addu_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x21); // addu t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 12;
state.registers[18] = 20;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_addi_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0x8, 17, 8, imm); // addi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_addui_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sub_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x22); // sub t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 20;
state.registers[18] = 12;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] - state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_subu_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x23); // subu t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 20;
state.registers[18] = 12;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] - state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_and_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x24); // and t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] & state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_andi_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xc, 17, 8, imm); // andi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] & imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_or_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x25); // or t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] | state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_ori_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xd, 17, 8, imm); // ori t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] | imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_xor_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x26); // xor t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] ^ state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_xori_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xe, 17, 8, imm); // xori t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] ^ imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_nor_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x27); // nor t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = ~(state.registers[17] | state.registers[18]); // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_slt_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
// swap and check again
uint32 tmp = state.registers[17];
state.registers[17] = state.registers[18];
state.registers[18] = tmp;
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sltu_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x2b); // sltu t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lb_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x20, 0x9, 0x8, 0x4); // lb $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_00_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lh_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_00_00;
uint32 insn = encodeitype(0x21, 0x9, 0x8, 0x4); // lh $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_23; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lw_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_45_67;
uint32 insn = encodeitype(0x23, 0x9, 0x8, 0x4); // lw $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = val; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lbu_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x24, 0x9, 0x8, 0x4); // lbu $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_23_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lhu_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x25, 0x9, 0x8, 0x4); // lhu $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_23_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_23; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lwl_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x22, 0x9, 0x8, 0x4); // lwl $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_34_56_78);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_34_56_78; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
// test unaligned address
insn = encodeitype(0x22, 0x9, 0x8, 0x5); // lwl $t0, 5($t1)
(state.memRoot, proof) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0x12_34_56_78);
expect.memRoot = state.memRoot;
expect.registers[8] = 0x34_56_78_dd; // t0
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lwr_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x26, 0x9, 0x8, 0x4); // lwr $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_34_56_78);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0xaa_bb_cc_12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
// test unaligned address
insn = encodeitype(0x26, 0x9, 0x8, 0x5); // lwr $t0, 5($t1)
(state.memRoot, proof) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0x12_34_56_78);
expect.memRoot = state.memRoot;
expect.registers[8] = 0xaa_bb_12_34; // t0
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sb_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x28, 0x9, 0x8, 0x4); // sb $t0, 4($t1)
// note. cannon memory is zero-initalized. mem[t+4] = 0 is a no-op
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xdd_00_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sh_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x29, 0x9, 0x8, 0x4); // sh $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xcc_dd_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_swl_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2a, 0x9, 0x8, 0x4); // swl $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sw_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2b, 0x9, 0x8, 0x4); // sw $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_swr_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2e, 0x9, 0x8, 0x5); // swr $t0, 5($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xcc_dd_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_ll_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_45_67;
uint32 insn = encodeitype(0x30, 0x9, 0x8, 0x4); // ll $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = val; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sc_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x38, 0x9, 0x8, 0x4); // sc $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x1;
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_movn_succeeds() external {
// test mips mov instruction
uint32 insn = encodespec(0x9, 0xa, 0x8, 0xb); // movn $t0, $t1, $t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xa; // t0
state.registers[9] = 0xb; // t1
state.registers[10] = 0x1; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9];
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
state.registers[10] = 0x0; // t2
expect.registers[10] = 0x0; // t2
expect.registers[8] = state.registers[8];
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_movz_succeeds() external {
// test mips mov instruction
uint32 insn = encodespec(0x9, 0xa, 0x8, 0xa); // movz $t0, $t1, $t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xa; // t0
state.registers[9] = 0xb; // t1
state.registers[10] = 0x0; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9];
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
state.registers[10] = 0x1; // t2
expect.registers[10] = 0x1; // t2
expect.registers[8] = state.registers[8];
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mflo_succeeds() external {
uint32 insn = encodespec(0x0, 0x0, 0x8, 0x12); // mflo $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.lo = 0xdeadbeef;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.lo = state.lo;
expect.registers[8] = state.lo;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mfhi_succeeds() external {
uint32 insn = encodespec(0x0, 0x0, 0x8, 0x10); // mfhi $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.hi = 0xdeadbeef;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.hi = state.hi;
expect.registers[8] = state.hi;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mthi_succeeds() external {
uint32 insn = encodespec(0x8, 0x0, 0x0, 0x11); // mthi $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.hi = state.registers[8];
expect.registers[8] = state.registers[8];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mtlo_succeeds() external {
uint32 insn = encodespec(0x8, 0x0, 0x0, 0x13); // mtlo $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.lo = state.registers[8];
expect.registers[8] = state.registers[8];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mul_succeeds() external {
uint32 insn = encodespec2(0x9, 0xa, 0x8, 0x2); // mul t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] * state.registers[10]; // t0
expect.registers[9] = 5;
expect.registers[10] = 2;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mult_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x18); // mult t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x0F_FF_00_00; // t1
state.registers[10] = 100; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 0x3F_9C_00_00;
expect.hi = 0x6;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_multu_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x19); // multu t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x0F_FF_00_00; // t1
state.registers[10] = 100; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 0x3F_9C_00_00;
expect.hi = 0x6;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_div_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x1a); // div t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 2;
expect.hi = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_divu_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x1b); // divu t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 2;
expect.hi = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_beq_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x4, 0x9, 0x8, boff); // beq $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xdeadbeef; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xdeadbeef;
expect.registers[9] = 0xdeadbeef;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
// branch not taken
state.registers[8] = 0xaa;
expect.registers[8] = 0xaa;
expect.nextPC = state.nextPC + 4;
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_bne_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x5, 0x9, 0x8, boff); // bne $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xaa; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xdeadbeef;
expect.registers[9] = 0xaa;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_blez_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x6, 0x8, 0x0, boff); // blez $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_bgtz_succeeds() external {
uint16 boff = 0xa0;
uint32 insn = encodeitype(0x7, 0x8, 0x0, boff); // bgtz $t0, 0xa0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_bltz_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x1, 0x8, 0x0, boff); // bltz $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xF0_00_00_00; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xF0_00_00_00;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_bgez_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x1, 0x8, 0x1, boff); // bgez $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0x00_00_00_01; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0x00_00_00_01;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_jump_succeeds() external {
uint16 label = 0x2;
uint32 insn = uint32(0x08_00_00_00) | label; // j label
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = label << 2;
expect.step = state.step + 1;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_jal_succeeds() external {
uint32 pc = 0x0;
uint16 label = 0x2;
uint32 insn = uint32(0x0c_00_00_00) | label; // jal label
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn);
MIPS.State memory state;
state.pc = 0;
state.nextPC = 4;
state.memRoot = memRoot;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = label << 2;
expect.step = state.step + 1;
expect.registers[31] = state.pc + 8;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_jr_succeeds() external {
uint16 tgt = 0x34;
uint32 insn = encodespec(0x8, 0, 0, 0x8); // jr t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = tgt;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = tgt;
expect.step = state.step + 1;
expect.registers[8] = tgt;
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_jalr_succeeds() external {
uint16 tgt = 0x34;
uint32 insn = encodespec(0x8, 0, 0x9, 0x9); // jalr t1, t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = tgt; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = tgt;
expect.step = state.step + 1;
expect.registers[8] = tgt;
expect.registers[9] = state.pc + 8; // t1
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sll_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6); // sll t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] << shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_srl_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 2); // srl t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sra_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_sllv_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 4); // sllv t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] << state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_srlv_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 6); // srlv t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20_00; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_srav_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 7); // srav t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20_00; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_lui_succeeds() external {
uint32 insn = encodeitype(0xf, 0x0, 0x8, 0x4); // lui $t0, 0x04
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x00_04_00_00; // t0
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_clo_succeeds() external {
uint32 insn = encodespec2(0x9, 0x0, 0x8, 0x21); // clo t0, t1
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0xFF_00_00_00; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 8; // t0
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_clz_succeeds() external {
uint32 insn = encodespec2(0x9, 0x0, 0x8, 0x20); // clz t0, t1
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x00_00_F0_00; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 16; // t0
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_preimage_read_succeeds() external {
uint32 pc = 0x0;
uint32 insn = 0x0000000c; // syscall
uint32 a1 = 0x4;
uint32 a1_val = 0x0000abba;
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn, a1, a1_val);
uint32[32] memory registers;
registers[2] = 4003; // read syscall
registers[4] = 5; // fd
registers[5] = a1; // addr
registers[6] = 4; // count
MIPS.State memory state = MIPS.State({
memRoot: memRoot,
preimageKey: bytes32(uint256(1) << 248 | 0x01),
preimageOffset: 8, // start reading past the pre-image length prefix
pc: pc,
nextPC: pc + 4,
lo: 0,
hi: 0,
heap: 0,
exitCode: 0,
exited: false,
step: 1,
registers: registers
});
bytes memory encodedState = encodeState(state);
// prime the pre-image oracle
bytes32 word = bytes32(uint256(0xdeadbeef) << 224);
uint8 size = 4;
uint8 partOffset = 8;
oracle.loadLocalData(uint256(state.preimageKey), word, size, partOffset);
MIPS.State memory expect = state;
expect.preimageOffset += 4;
expect.pc = state.nextPC;
expect.nextPC += 4;
expect.step += 1;
expect.registers[2] = 4; // return
expect.registers[7] = 0; // errno
// recompute merkle root of written pre-image
(expect.memRoot,) = ffi.getCannonMemoryProof(pc, insn, a1, 0xdeadbeef);
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_preimage_write_succeeds() external {
uint32 pc = 0x0;
uint32 insn = 0x0000000c; // syscall
uint32 a1 = 0x4;
uint32 a1_val = 0x0000abba;
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn, a1, a1_val);
uint32[32] memory registers;
registers[2] = 4004; // write syscall
registers[4] = 6; // fd
registers[5] = a1; // addr
registers[6] = 4; // count
MIPS.State memory state = MIPS.State({
memRoot: memRoot,
preimageKey: bytes32(0),
preimageOffset: 1,
pc: pc,
nextPC: 4,
lo: 0,
hi: 0,
heap: 0,
exitCode: 0,
exited: false,
step: 1,
registers: registers
});
bytes memory encodedState = encodeState(state);
MIPS.State memory expect = state;
expect.preimageOffset = 0; // preimage write resets offset
expect.pc = state.nextPC;
expect.nextPC += 4;
expect.step += 1;
expect.preimageKey = bytes32(uint256(0xabba));
expect.registers[2] = 4; // return
expect.registers[7] = 0; // errno
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mmap_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn);
MIPS.State memory state;
state.memRoot = memRoot;
state.nextPC = 4;
state.registers[2] = 4090; // mmap syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 4095; // a1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
// assert page allocation is aligned to 4k
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.heap = state.heap + 4096;
expect.registers[2] = 0; // return old heap
expect.registers[4] = 0x0; // a0
expect.registers[5] = 4095; // a1
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_brk_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4045; // brk syscall
state.registers[4] = 0xdead;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.registers[2] = 0x40000000;
expect.registers[4] = state.registers[4]; // registers unchanged
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_clone_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4120; // clone syscall
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.registers[2] = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_exit_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4246; // exit_group syscall
state.registers[4] = 0x5; // a0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.pc;
expect.nextPC = state.nextPC;
expect.step = state.step + 1;
expect.registers[2] = state.registers[2]; // unchanged
expect.registers[4] = state.registers[4]; // unchanged
expect.exited = true;
expect.exitCode = uint8(state.registers[4]);
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_fcntl_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4055; // fnctl syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 0x3; // a1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[2] = 0;
expect.registers[5] = state.registers[5];
bytes32 postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
// assert O_WRONLY
state.registers[4] = 0x1; // a0
expect.registers[4] = state.registers[4];
expect.registers[2] = 1;
postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_prestate_exited_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.exited = true;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertEq(postState, outputState(state), "unexpected post state");
}
function test_illegal_instruction_fails() external {
uint32 illegal_insn = 0xFF_FF_FF_FF;
// the illegal instruction is partially decoded as containing a memory operand
// so we stuff random data to the expected address
uint32 addr = 0xFF_FF_FF_FC; // 4-byte aligned ff..ff
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, illegal_insn, addr, 0);
MIPS.State memory state;
state.memRoot = memRoot;
bytes memory encodedState = encodeState(state);
vm.expectRevert("invalid instruction");
mips.step(encodedState, proof);
}
function test_invalid_root_fails() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4246; // exit_group syscall
state.registers[4] = 0x5; // a0
// invalidate proof
for (uint256 i = 0; i < proof.length; i++) {
proof[i] = 0x0;
}
vm.expectRevert(hex"000000000000000000000000000000000000000000000000000000000badf00d");
mips.step(encodeState(state), proof);
}
function test_jump_inDelaySlot_fails() external {
uint16 label = 0x2;
uint32 insn = uint32(0x08_00_00_00) | label; // j label
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.nextPC = 0xa;
vm.expectRevert("jump in delay slot");
mips.step(encodeState(state), proof);
}
function test_branch_inDelaySlot_fails() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x4, 0x9, 0x8, boff); // beq $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xdeadbeef; // t1
state.nextPC = 0xa;
vm.expectRevert("branch in delay slot");
mips.step(encodeState(state), proof);
}
function encodeState(MIPS.State memory state) internal pure returns (bytes memory) {
bytes memory registers;
for (uint256 i = 0; i < state.registers.length; i++) {
......@@ -61,4 +1504,37 @@ contract MIPS_Test is Test {
registers
);
}
function outputState(MIPS.State memory state) internal pure returns (bytes32 out_) {
bytes memory enc = encodeState(state);
assembly {
out_ := keccak256(add(enc, 0x20), 226)
}
}
function constructMIPSState(
uint32 pc,
uint32 insn,
uint32 addr,
uint32 val
)
internal
returns (MIPS.State memory state, bytes memory proof)
{
(state.memRoot, proof) = ffi.getCannonMemoryProof(pc, insn, addr, val);
state.pc = pc;
state.nextPC = pc + 4;
}
function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn) {
insn = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm;
}
function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn) {
insn = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct);
}
function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn) {
insn = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct);
}
}
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