Skip to content

Commit 6a32d19

Browse files
committed
feat(evmreader): add support for PRT applications
1 parent 3c01d94 commit 6a32d19

8 files changed

Lines changed: 646 additions & 32 deletions

File tree

internal/evmreader/application_adapter.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ import (
1717
"github.com/ethereum/go-ethereum/ethclient"
1818
)
1919

20+
type ApplicationContractAdapter interface {
21+
RetrieveOutputExecutionEvents(
22+
opts *bind.FilterOpts,
23+
) ([]*iapplication.IApplicationOutputExecuted, error)
24+
GetDeploymentBlockNumber(opts *bind.CallOpts) (*big.Int, error)
25+
}
26+
2027
// IApplication Wrapper
2128
type ApplicationContractAdapterImpl struct {
2229
application *iapplication.IApplication
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// (c) Cartesi and individual authors (see AUTHORS)
2+
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
3+
4+
package evmreader
5+
6+
import (
7+
"math/big"
8+
9+
. "github.com/cartesi/rollups-node/internal/model"
10+
"github.com/cartesi/rollups-node/pkg/contracts/daveconsensus"
11+
"github.com/cartesi/rollups-node/pkg/ethutil"
12+
13+
"github.com/ethereum/go-ethereum"
14+
"github.com/ethereum/go-ethereum/accounts/abi"
15+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
16+
"github.com/ethereum/go-ethereum/common"
17+
"github.com/ethereum/go-ethereum/ethclient"
18+
)
19+
20+
// Interface for DaveConsensus reading
21+
type DaveConsensusAdapter interface {
22+
GetInputBox(opts *bind.CallOpts) (common.Address, error)
23+
GetCurrentSealedEpoch(opts *bind.CallOpts) (struct {
24+
EpochNumber *big.Int
25+
InputIndexLowerBound *big.Int
26+
InputIndexUpperBound *big.Int
27+
Tournament common.Address
28+
}, error)
29+
GetApplicationContract(opts *bind.CallOpts) (common.Address, error)
30+
GetTournamentFactory(opts *bind.CallOpts) (common.Address, error)
31+
RetrieveSealedEpochs(opts *bind.FilterOpts) ([]*daveconsensus.DaveConsensusEpochSealed, error)
32+
}
33+
34+
// DaveConsensus Wrapper
35+
type DaveConsensusAdapterImpl struct {
36+
daveConsensus *daveconsensus.DaveConsensus
37+
client *ethclient.Client
38+
daveConsensusAddress common.Address
39+
filter ethutil.Filter
40+
}
41+
42+
func NewDaveConsensusAdapter(
43+
daveConsensusAddress common.Address,
44+
client *ethclient.Client,
45+
filter ethutil.Filter,
46+
) (DaveConsensusAdapter, error) {
47+
daveConsensusContract, err := daveconsensus.NewDaveConsensus(daveConsensusAddress, client)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return &DaveConsensusAdapterImpl{
52+
daveConsensus: daveConsensusContract,
53+
daveConsensusAddress: daveConsensusAddress,
54+
client: client,
55+
filter: filter,
56+
}, nil
57+
}
58+
59+
func buildEpochSealedFilterQuery(
60+
opts *bind.FilterOpts,
61+
daveConsensusAddress common.Address,
62+
) (q ethereum.FilterQuery, err error) {
63+
c, err := daveconsensus.DaveConsensusMetaData.GetAbi()
64+
if err != nil {
65+
return q, err
66+
}
67+
68+
topics, err := abi.MakeTopics(
69+
[]any{c.Events[MonitoredEvent_EpochSealed.String()].ID},
70+
)
71+
if err != nil {
72+
return q, err
73+
}
74+
75+
q = ethereum.FilterQuery{
76+
Addresses: []common.Address{daveConsensusAddress},
77+
FromBlock: new(big.Int).SetUint64(opts.Start),
78+
Topics: topics,
79+
}
80+
if opts.End != nil {
81+
q.ToBlock = new(big.Int).SetUint64(*opts.End)
82+
}
83+
return q, err
84+
}
85+
86+
func (d *DaveConsensusAdapterImpl) GetInputBox(opts *bind.CallOpts) (common.Address, error) {
87+
return d.daveConsensus.GetInputBox(opts)
88+
}
89+
90+
func (d *DaveConsensusAdapterImpl) GetCurrentSealedEpoch(opts *bind.CallOpts) (struct {
91+
EpochNumber *big.Int
92+
InputIndexLowerBound *big.Int
93+
InputIndexUpperBound *big.Int
94+
Tournament common.Address
95+
}, error) {
96+
return d.daveConsensus.GetCurrentSealedEpoch(opts)
97+
}
98+
99+
func (d *DaveConsensusAdapterImpl) GetApplicationContract(opts *bind.CallOpts) (common.Address, error) {
100+
return d.daveConsensus.GetApplicationContract(opts)
101+
}
102+
103+
func (d *DaveConsensusAdapterImpl) GetTournamentFactory(opts *bind.CallOpts) (common.Address, error) {
104+
return d.daveConsensus.GetTournamentFactory(opts)
105+
}
106+
107+
func (d *DaveConsensusAdapterImpl) RetrieveSealedEpochs(
108+
opts *bind.FilterOpts,
109+
) ([]*daveconsensus.DaveConsensusEpochSealed, error) {
110+
q, err := buildEpochSealedFilterQuery(opts, d.daveConsensusAddress)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
itr, err := d.filter.ChunkedFilterLogs(opts.Context, d.client, q)
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
var events []*daveconsensus.DaveConsensusEpochSealed
121+
for log, err := range itr {
122+
if err != nil {
123+
return nil, err
124+
}
125+
ev, err := d.daveConsensus.ParseEpochSealed(*log)
126+
if err != nil {
127+
return nil, err
128+
}
129+
events = append(events, ev)
130+
}
131+
return events, nil
132+
}

internal/evmreader/evmreader.go

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@ import (
1111
"time"
1212

1313
"github.com/ethereum/go-ethereum"
14-
"github.com/ethereum/go-ethereum/accounts/abi/bind"
15-
"github.com/ethereum/go-ethereum/common"
1614
"github.com/ethereum/go-ethereum/core/types"
1715
"github.com/ethereum/go-ethereum/ethclient"
1816
"github.com/ethereum/go-ethereum/rpc"
1917

2018
. "github.com/cartesi/rollups-node/internal/model"
2119
"github.com/cartesi/rollups-node/internal/repository"
22-
"github.com/cartesi/rollups-node/pkg/contracts/iapplication"
23-
"github.com/cartesi/rollups-node/pkg/contracts/iinputbox"
2420
"github.com/cartesi/rollups-node/pkg/ethutil"
2521
)
2622

@@ -40,6 +36,7 @@ type EvmReaderRepository interface {
4036
) error
4137
GetEpoch(ctx context.Context, nameOrAddress string, index uint64) (*Epoch, error)
4238
ListEpochs(ctx context.Context, nameOrAddress string, f repository.EpochFilter, p repository.Pagination, descending bool) ([]*Epoch, uint64, error)
39+
UpdateEpoch(ctx context.Context, nameOrAddress string, e *Epoch) error
4340

4441
// Output execution monitor
4542
GetOutput(ctx context.Context, nameOrAddress string, indexKey uint64) (*Output, error)
@@ -53,22 +50,6 @@ type EthClientInterface interface {
5350
ChainID(ctx context.Context) (*big.Int, error)
5451
}
5552

56-
type ApplicationContractAdapter interface {
57-
RetrieveOutputExecutionEvents(
58-
opts *bind.FilterOpts,
59-
) ([]*iapplication.IApplicationOutputExecuted, error)
60-
GetDeploymentBlockNumber(opts *bind.CallOpts) (*big.Int, error)
61-
}
62-
63-
// Interface for Input reading
64-
type InputSourceAdapter interface {
65-
// Wrapper for FilterInputAdded(), which is automatically generated
66-
// by go-ethereum and cannot be used for testing
67-
RetrieveInputs(opts *bind.FilterOpts, appAddresses []common.Address, index []*big.Int,
68-
) ([]iinputbox.IInputBoxInputAdded, error)
69-
GetNumberOfInputs(opts *bind.CallOpts, appContract common.Address) (*big.Int, error)
70-
}
71-
7253
type SubscriptionError struct {
7354
Cause error
7455
}
@@ -82,6 +63,7 @@ type appContracts struct {
8263
application *Application
8364
applicationContract ApplicationContractAdapter
8465
inputSource InputSourceAdapter
66+
daveConsensus DaveConsensusAdapter
8567
}
8668

8769
func (r *Service) Run(ctx context.Context, ready chan struct{}) error {
@@ -151,8 +133,10 @@ func (r *Service) watchForNewBlocks(ctx context.Context, ready chan<- struct{})
151133

152134
// Build Contracts
153135
var apps []appContracts
136+
var daveConsensusApps []appContracts
137+
var iconsensusApps []appContracts
154138
for _, app := range runningApps {
155-
applicationContract, inputSource, err := r.adapterFactory.CreateAdapters(app, r.client)
139+
applicationContract, inputSource, daveConsensus, err := r.adapterFactory.CreateAdapters(app, r.client)
156140

157141
if err != nil {
158142
r.Logger.Error("Error retrieving application contracts", "app", app, "error", err)
@@ -162,9 +146,15 @@ func (r *Service) watchForNewBlocks(ctx context.Context, ready chan<- struct{})
162146
application: app,
163147
applicationContract: applicationContract,
164148
inputSource: inputSource,
149+
daveConsensus: daveConsensus,
165150
}
166151

167152
apps = append(apps, aContracts)
153+
if app.DaveConsensus {
154+
daveConsensusApps = append(daveConsensusApps, aContracts)
155+
} else {
156+
iconsensusApps = append(iconsensusApps, aContracts)
157+
}
168158
}
169159

170160
if len(apps) == 0 {
@@ -190,7 +180,9 @@ func (r *Service) watchForNewBlocks(ctx context.Context, ready chan<- struct{})
190180
mostRecentHeader.Number.Uint64(), header.Number.Uint64(), r.defaultBlock))
191181
}
192182

193-
r.checkForNewInputs(ctx, apps, blockNumber)
183+
r.checkForEpochsAndInputs(ctx, daveConsensusApps, blockNumber)
184+
185+
r.checkForNewInputs(ctx, iconsensusApps, blockNumber)
194186

195187
r.checkForOutputExecution(ctx, apps, blockNumber)
196188

@@ -234,39 +226,50 @@ func (r *Service) fetchMostRecentHeader(
234226
}
235227

236228
type AdapterFactory interface {
237-
CreateAdapters(app *Application, client EthClientInterface) (ApplicationContractAdapter, InputSourceAdapter, error)
229+
CreateAdapters(app *Application, client EthClientInterface) (ApplicationContractAdapter, InputSourceAdapter, DaveConsensusAdapter, error)
238230
}
239231

240232
type DefaultAdapterFactory struct {
241233
Filter ethutil.Filter
242234
}
243235

244-
func (f *DefaultAdapterFactory) CreateAdapters(app *Application, client EthClientInterface) (ApplicationContractAdapter, InputSourceAdapter, error) {
236+
func (f *DefaultAdapterFactory) CreateAdapters(app *Application, client EthClientInterface) (ApplicationContractAdapter, InputSourceAdapter, DaveConsensusAdapter, error) {
245237
if app == nil {
246-
return nil, nil, fmt.Errorf("Application reference is nil. Should never happen")
238+
return nil, nil, nil, fmt.Errorf("Application reference is nil. Should never happen")
247239
}
248240

249241
// Type assertion to get the concrete client if possible
250242
ethClient, ok := client.(*ethclient.Client)
251243
if !ok {
252-
return nil, nil, fmt.Errorf("client is not an *ethclient.Client, cannot create adapters")
244+
return nil, nil, nil, fmt.Errorf("client is not an *ethclient.Client, cannot create adapters")
253245
}
254246

255247
applicationContract, err := NewApplicationContractAdapter(app.IApplicationAddress, ethClient, f.Filter)
256248
if err != nil {
257-
return nil, nil, errors.Join(
249+
return nil, nil, nil, errors.Join(
258250
fmt.Errorf("error building application contract"),
259251
err,
260252
)
261253
}
262254

263255
inputSource, err := NewInputSourceAdapter(app.IInputBoxAddress, ethClient, f.Filter)
264256
if err != nil {
265-
return nil, nil, errors.Join(
257+
return nil, nil, nil, errors.Join(
266258
fmt.Errorf("error building inputbox contract"),
267259
err,
268260
)
269261
}
270262

271-
return applicationContract, inputSource, nil
263+
var daveConsensus DaveConsensusAdapter
264+
if app.DaveConsensus {
265+
daveConsensus, err = NewDaveConsensusAdapter(app.IConsensusAddress, ethClient, f.Filter)
266+
if err != nil {
267+
return nil, nil, nil, errors.Join(
268+
fmt.Errorf("error building daveconsensus contract"),
269+
err,
270+
)
271+
}
272+
}
273+
274+
return applicationContract, inputSource, daveConsensus, nil
272275
}

internal/evmreader/evmreader_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,11 @@ func (m *MockRepository) GetOutput(ctx context.Context, nameOrAddress string, in
536536
return obj.(*Output), args.Error(1)
537537
}
538538

539+
func (m *MockRepository) UpdateEpoch(ctx context.Context, nameOrAddress string, e *Epoch) error {
540+
args := m.Called(ctx, nameOrAddress, e)
541+
return args.Error(0)
542+
}
543+
539544
func (m *MockRepository) UpdateOutputsExecution(ctx context.Context, nameOrAddress string,
540545
executedOutputs []*Output, blockNumber uint64) error {
541546
args := m.Called(ctx, nameOrAddress, executedOutputs, blockNumber)
@@ -592,7 +597,7 @@ func (m *MockAdapterFactory) Unset(methodName string) {
592597
func (m *MockAdapterFactory) CreateAdapters(
593598
app *Application,
594599
client EthClientInterface,
595-
) (ApplicationContractAdapter, InputSourceAdapter, error) {
600+
) (ApplicationContractAdapter, InputSourceAdapter, DaveConsensusAdapter, error) {
596601
args := m.Called(app, client)
597602

598603
// Safely handle nil values to prevent interface conversion panic
@@ -608,7 +613,7 @@ func (m *MockAdapterFactory) CreateAdapters(
608613
inputSource = newMockInputBox()
609614
}
610615

611-
return appContract, inputSource, args.Error(2)
616+
return appContract, inputSource, nil, args.Error(2)
612617
}
613618

614619
func newMockAdapterFactory() *MockAdapterFactory {

internal/evmreader/inputsource_adapter.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ import (
1717
"github.com/ethereum/go-ethereum/ethclient"
1818
)
1919

20+
// Interface for Input reading
21+
type InputSourceAdapter interface {
22+
// Wrapper for FilterInputAdded(), which is automatically generated
23+
// by go-ethereum and cannot be used for testing
24+
RetrieveInputs(opts *bind.FilterOpts, appAddresses []common.Address, index []*big.Int,
25+
) ([]iinputbox.IInputBoxInputAdded, error)
26+
GetNumberOfInputs(opts *bind.CallOpts, appContract common.Address) (*big.Int, error)
27+
}
28+
2029
// InputBox Wrapper
2130
type InputSourceAdapterImpl struct {
2231
inputbox *iinputbox.IInputBox

internal/evmreader/output.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func (r *Service) checkForOutputExecution(
6767
"most_recent_block", mostRecentBlockNumber,
6868
)
6969
} else {
70-
r.Logger.Warn("Not reading output execution: already checked the most recent blocks",
70+
r.Logger.Debug("Not reading output execution: already checked the most recent blocks",
7171
"application", app.application.Name, "address", app.application.IApplicationAddress,
7272
"last output check block", lastOutputCheck,
7373
"most recent block", mostRecentBlockNumber,

0 commit comments

Comments
 (0)