-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(evm-reader): Read output execution statuses
- Loading branch information
Showing
14 changed files
with
679 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
package evmreader | ||
|
||
import ( | ||
appcontract "github.com/cartesi/rollups-node/pkg/contracts/application" | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
) | ||
|
||
// IConsensus Wrapper | ||
type ApplicationContractAdapter struct { | ||
application *appcontract.Application | ||
} | ||
|
||
func NewApplicationContractAdapter( | ||
appAddress common.Address, | ||
client *ethclient.Client, | ||
) (*ApplicationContractAdapter, error) { | ||
applicationContract, err := appcontract.NewApplication(appAddress, client) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &ApplicationContractAdapter{ | ||
application: applicationContract, | ||
}, nil | ||
} | ||
|
||
func (a *ApplicationContractAdapter) GetConsensus(opts *bind.CallOpts) (common.Address, error) { | ||
return a.application.GetConsensus(opts) | ||
} | ||
|
||
func (a *ApplicationContractAdapter) RetrieveOutputExecutionEvents( | ||
opts *bind.FilterOpts, | ||
) ([]*appcontract.ApplicationOutputExecuted, error) { | ||
|
||
itr, err := a.application.FilterOutputExecuted(opts) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer itr.Close() | ||
|
||
var events []*appcontract.ApplicationOutputExecuted | ||
for itr.Next() { | ||
outputExecutedEvent := itr.Event | ||
events = append(events, outputExecutedEvent) | ||
} | ||
err = itr.Error() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return events, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
package evmreader | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"log/slog" | ||
|
||
. "github.com/cartesi/rollups-node/internal/node/model" | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
) | ||
|
||
func (r *EvmReader) checkForOutputExecution( | ||
ctx context.Context, | ||
apps []application, | ||
mostRecentBlockNumber uint64, | ||
) { | ||
|
||
appAddresses := appToAddresses(apps) | ||
|
||
slog.Debug("Checking for new Output Executed Events", "apps", appAddresses) | ||
|
||
for _, app := range apps { | ||
|
||
LastOutputCheck := app.LastOutputCheckBlock | ||
|
||
// Safeguard: Only check blocks starting from the block where the InputBox | ||
// contract was deployed as Inputs can be added to that same block | ||
if LastOutputCheck < r.inputBoxDeploymentBlock { | ||
LastOutputCheck = r.inputBoxDeploymentBlock | ||
} | ||
|
||
if mostRecentBlockNumber > LastOutputCheck { | ||
|
||
slog.Info("Checking output execution for applications", | ||
"apps", appAddresses, | ||
"last output check block", LastOutputCheck, | ||
"most recent block", mostRecentBlockNumber) | ||
|
||
r.readAndUpdateOutputs(ctx, app, LastOutputCheck, mostRecentBlockNumber) | ||
|
||
} else if mostRecentBlockNumber < LastOutputCheck { | ||
slog.Warn( | ||
"Not reading output execution: most recent block is lower than the last processed one", //nolint:lll | ||
"apps", appAddresses, | ||
"last output check block", LastOutputCheck, | ||
"most recent block", mostRecentBlockNumber, | ||
) | ||
} else { | ||
slog.Info("Not reading output execution: already checked the most recent blocks", | ||
"apps", appAddresses, | ||
"last output check block", LastOutputCheck, | ||
"most recent block", mostRecentBlockNumber, | ||
) | ||
} | ||
} | ||
|
||
} | ||
|
||
func (r *EvmReader) readAndUpdateOutputs( | ||
ctx context.Context, app application, lastOutputCheck, mostRecentBlockNumber uint64) { | ||
|
||
contract := app.applicationContract | ||
|
||
opts := &bind.FilterOpts{ | ||
Start: lastOutputCheck + 1, | ||
End: &mostRecentBlockNumber, | ||
} | ||
|
||
outputExecutedEvents, err := contract.RetrieveOutputExecutionEvents(opts) | ||
if err != nil { | ||
slog.Error("Error reading output events", "app", app.ContractAddress, "error", err) | ||
return | ||
} | ||
|
||
// Should we check the output hash?? | ||
var executedOutputs []*Output | ||
for _, event := range outputExecutedEvents { | ||
|
||
// Compare output to check it is the correct one | ||
output, err := r.repository.GetOutput(ctx, event.OutputIndex, app.ContractAddress) | ||
if err != nil { | ||
slog.Error("Error retrieving output", | ||
"app", app.ContractAddress, "index", event.OutputIndex, "error", err) | ||
return | ||
} | ||
|
||
if !bytes.Equal(output.RawData, event.Output) { | ||
slog.Debug("Actual output differs from event's", | ||
"app", app.ContractAddress, "index", event.OutputIndex, | ||
"actual", output.RawData, "event's", event.Output) | ||
|
||
slog.Error("Output mismatch", "app", app.ContractAddress, "index", event.OutputIndex) | ||
|
||
return | ||
} | ||
|
||
slog.Info("Output executed", "app", app, "index", event.OutputIndex) | ||
output.TransactionHash = &event.Raw.TxHash | ||
executedOutputs = append(executedOutputs, output) | ||
} | ||
|
||
err = r.repository.UpdateOutputExecutionTransaction( | ||
ctx, app.ContractAddress, executedOutputs, mostRecentBlockNumber) | ||
if err != nil { | ||
slog.Error("Error storing output execution statuses", "app", app, "error", err) | ||
} | ||
|
||
} |
Oops, something went wrong.