Skip to content

Commit

Permalink
Merge branch 'master' into pathdb_fullnode
Browse files Browse the repository at this point in the history
  • Loading branch information
diegoximenes authored Jul 23, 2024
2 parents 97b5bda + 9197ebe commit 44a15ea
Show file tree
Hide file tree
Showing 10 changed files with 848 additions and 16 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ go-ethereum/tests
**/*.yml
contracts/build
contracts/cache/
safe-smart-account/build/
solgen/go
**/node_modules

Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@
[submodule "arbitrator/langs/bf"]
path = arbitrator/langs/bf
url = https://github.com/OffchainLabs/stylus-sdk-bf.git
[submodule "safe-smart-account"]
path = safe-smart-account
url = https://github.com/safe-global/safe-smart-account.git
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ WORKDIR /workspace
COPY contracts/package.json contracts/yarn.lock contracts/
RUN cd contracts && yarn install
COPY contracts contracts/
COPY safe-smart-account safe-smart-account/
RUN cd safe-smart-account && yarn install
COPY Makefile .
RUN . ~/.bashrc && NITRO_BUILD_IGNORE_TIMESTAMPS=1 make build-solidity

Expand Down Expand Up @@ -82,6 +84,7 @@ COPY ./wavmio ./wavmio
COPY ./zeroheavy ./zeroheavy
COPY ./contracts/src/precompiles/ ./contracts/src/precompiles/
COPY ./contracts/package.json ./contracts/yarn.lock ./contracts/
COPY ./safe-smart-account ./safe-smart-account
COPY ./solgen/gen.go ./solgen/
COPY ./fastcache ./fastcache
COPY ./go-ethereum ./go-ethereum
Expand Down Expand Up @@ -179,6 +182,7 @@ COPY ./Makefile ./
COPY ./arbitrator ./arbitrator
COPY ./solgen ./solgen
COPY ./contracts ./contracts
COPY ./safe-smart-account ./safe-smart-account
RUN NITRO_BUILD_IGNORE_TIMESTAMPS=1 make build-replay-env

FROM debian:bookworm-slim AS machine-versions
Expand Down Expand Up @@ -226,6 +230,7 @@ COPY . ./
COPY --from=contracts-builder workspace/contracts/build/ contracts/build/
COPY --from=contracts-builder workspace/contracts/out/ contracts/out/
COPY --from=contracts-builder workspace/contracts/node_modules/@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json contracts/node_modules/@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/
COPY --from=contracts-builder workspace/safe-smart-account/build/ safe-smart-account/build/
COPY --from=contracts-builder workspace/.make/ .make/
COPY --from=prover-header-export / target/
COPY --from=brotli-library-export / target/
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,14 @@ contracts/test/prover/proofs/%.json: $(arbitrator_cases)/%.wasm $(prover_bin)
go run solgen/gen.go
@touch $@

.make/solidity: $(DEP_PREDICATE) contracts/src/*/*.sol .make/yarndeps $(ORDER_ONLY_PREDICATE) .make
.make/solidity: $(DEP_PREDICATE) safe-smart-account/contracts/*/*.sol safe-smart-account/contracts/*.sol contracts/src/*/*.sol .make/yarndeps $(ORDER_ONLY_PREDICATE) .make
yarn --cwd safe-smart-account build
yarn --cwd contracts build
yarn --cwd contracts build:forge:yul
@touch $@

.make/yarndeps: $(DEP_PREDICATE) contracts/package.json contracts/yarn.lock $(ORDER_ONLY_PREDICATE) .make
yarn --cwd safe-smart-account install
yarn --cwd contracts install
@touch $@

Expand Down
1 change: 1 addition & 0 deletions safe-smart-account
Submodule safe-smart-account added at 192c7d
12 changes: 12 additions & 0 deletions solgen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ func main() {
log.Fatal(err)
}

filePathsSafeSmartAccount, err := filepath.Glob(filepath.Join(parent, "safe-smart-account", "build", "artifacts", "contracts", "*", "*.sol", "*.json"))
if err != nil {
log.Fatal(err)
}
filePathsSafeSmartAccountOuter, err := filepath.Glob(filepath.Join(parent, "safe-smart-account", "build", "artifacts", "contracts", "*.sol", "*.json"))
if err != nil {
log.Fatal(err)
}

filePaths = append(filePaths, filePathsSafeSmartAccount...)
filePaths = append(filePaths, filePathsSafeSmartAccountOuter...)

modules := make(map[string]*moduleInfo)

for _, path := range filePaths {
Expand Down
239 changes: 239 additions & 0 deletions staker/fast_confirm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// Copyright 2023-2024, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

package staker

import (
"context"
"errors"
"fmt"
"math/big"
"sort"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"

"github.com/offchainlabs/nitro/solgen/go/contractsgen"
"github.com/offchainlabs/nitro/solgen/go/rollupgen"
"github.com/offchainlabs/nitro/staker/txbuilder"
"github.com/offchainlabs/nitro/util/headerreader"
)

type FastConfirmSafe struct {
safe *contractsgen.Safe
owners []common.Address
threshold uint64
fastConfirmNextNodeMethod abi.Method
builder *txbuilder.Builder
wallet ValidatorWalletInterface
gasRefunder common.Address
l1Reader *headerreader.HeaderReader
}

func NewFastConfirmSafe(
callOpts bind.CallOpts,
fastConfirmSafeAddress common.Address,
builder *txbuilder.Builder,
wallet ValidatorWalletInterface,
gasRefunder common.Address,
l1Reader *headerreader.HeaderReader,
) (*FastConfirmSafe, error) {
fastConfirmSafe := &FastConfirmSafe{
builder: builder,
wallet: wallet,
gasRefunder: gasRefunder,
l1Reader: l1Reader,
}
safe, err := contractsgen.NewSafe(fastConfirmSafeAddress, builder)
if err != nil {
return nil, err
}
fastConfirmSafe.safe = safe
owners, err := safe.GetOwners(&callOpts)
if err != nil {
return nil, err
}

// This is needed because safe contract needs owners to be sorted.
sort.Slice(owners, func(i, j int) bool {
return owners[i].Cmp(owners[j]) < 0
})
fastConfirmSafe.owners = owners
threshold, err := safe.GetThreshold(&callOpts)
if err != nil {
return nil, err
}
fastConfirmSafe.threshold = threshold.Uint64()
rollupUserLogicAbi, err := rollupgen.RollupUserLogicMetaData.GetAbi()
if err != nil {
return nil, err
}
fastConfirmNextNodeMethod, ok := rollupUserLogicAbi.Methods["fastConfirmNextNode"]
if !ok {
return nil, errors.New("RollupUserLogic ABI missing fastConfirmNextNode method")
}
fastConfirmSafe.fastConfirmNextNodeMethod = fastConfirmNextNodeMethod
return fastConfirmSafe, nil
}

func (f *FastConfirmSafe) tryFastConfirmation(ctx context.Context, blockHash common.Hash, sendRoot common.Hash) error {
fastConfirmCallData, err := f.createFastConfirmCalldata(blockHash, sendRoot)
if err != nil {
return err
}
callOpts := &bind.CallOpts{Context: ctx}
// Current nonce of the safe.
nonce, err := f.safe.Nonce(callOpts)
if err != nil {
return err
}
// Hash of the safe transaction.
safeTxHash, err := f.safe.GetTransactionHash(
callOpts,
f.wallet.RollupAddress(),
big.NewInt(0),
fastConfirmCallData,
0,
big.NewInt(0),
big.NewInt(0),
big.NewInt(0),
common.Address{},
common.Address{},
nonce,
)
if err != nil {
return err
}
if !f.wallet.CanBatchTxs() {
err = f.flushTransactions(ctx)
if err != nil {
return err
}
}
auth, err := f.builder.Auth(ctx)
if err != nil {
return err
}
_, err = f.safe.ApproveHash(auth, safeTxHash)
if err != nil {
return err
}
if !f.wallet.CanBatchTxs() {
err = f.flushTransactions(ctx)
if err != nil {
return err
}
}
executedTx, err := f.checkApprovedHashAndExecTransaction(ctx, fastConfirmCallData, safeTxHash)
if err != nil {
return err
}
if executedTx {
return nil
}
// If the transaction was not executed, we need to flush the transactions (for approve hash) and try again.
// This is because the hash might have been approved by another wallet in the same block,
// which might have led to a race condition.
err = f.flushTransactions(ctx)
if err != nil {
return err
}
_, err = f.checkApprovedHashAndExecTransaction(ctx, fastConfirmCallData, safeTxHash)
return err
}

func (f *FastConfirmSafe) flushTransactions(ctx context.Context) error {
arbTx, err := f.wallet.ExecuteTransactions(ctx, f.builder, f.gasRefunder)
if err != nil {
return err
}
if arbTx != nil {
_, err = f.l1Reader.WaitForTxApproval(ctx, arbTx)
if err == nil {
log.Info("successfully executed staker transaction", "hash", arbTx.Hash())
} else {
return fmt.Errorf("error waiting for tx receipt: %w", err)
}
}
f.builder.ClearTransactions()
return nil
}

func (f *FastConfirmSafe) createFastConfirmCalldata(
blockHash common.Hash, sendRoot common.Hash,
) ([]byte, error) {
calldata, err := f.fastConfirmNextNodeMethod.Inputs.Pack(
blockHash,
sendRoot,
)
if err != nil {
return nil, err
}
fullCalldata := append([]byte{}, f.fastConfirmNextNodeMethod.ID...)
fullCalldata = append(fullCalldata, calldata...)
return fullCalldata, nil
}

func (f *FastConfirmSafe) checkApprovedHashAndExecTransaction(ctx context.Context, fastConfirmCallData []byte, safeTxHash [32]byte) (bool, error) {
var signatures []byte
approvedHashCount := uint64(0)
for _, owner := range f.owners {
if f.wallet.Address() == nil {
return false, errors.New("wallet address is nil")
}
var approved *big.Int
// No need check if wallet has approved the hash,
// since checkApprovedHashAndExecTransaction is called only after wallet has approved the hash.
if *f.wallet.Address() == owner {
approved = common.Big1
} else {
var err error
approved, err = f.safe.ApprovedHashes(&bind.CallOpts{Context: ctx}, owner, safeTxHash)
if err != nil {
return false, err
}
}

// If the owner has approved the hash, we add the signature to the transaction.
// We add the signature in the format r, s, v.
// We set v to 1, as it is the only possible value for a approved hash.
// We set r to the owner's address.
// We set s to the empty hash.
// Refer to the Safe contract for more information.
if approved.Cmp(common.Big1) == 0 {
approvedHashCount++
v := uint8(1)
r := common.BytesToHash(owner.Bytes())
s := common.Hash{}
signatures = append(signatures, r.Bytes()...)
signatures = append(signatures, s.Bytes()...)
signatures = append(signatures, v)
}
}
if approvedHashCount >= f.threshold {
auth, err := f.builder.Auth(ctx)
if err != nil {
return false, err
}
_, err = f.safe.ExecTransaction(
auth,
f.wallet.RollupAddress(),
big.NewInt(0),
fastConfirmCallData,
0,
big.NewInt(0),
big.NewInt(0),
big.NewInt(0),
common.Address{},
common.Address{},
signatures,
)
if err != nil {
return false, err
}
return true, nil
}
return false, nil
}
Loading

0 comments on commit 44a15ea

Please sign in to comment.