Skip to content

Commit 412e746

Browse files
committed
sc: transfer bridge data to NillRollup
1 parent a89096f commit 412e746

File tree

18 files changed

+264
-1670
lines changed

18 files changed

+264
-1670
lines changed

nil/services/synccommittee/Makefile.inc

+20-11
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ root_contracts = rollup-bridge-contracts/contracts
33

44
.PHONY: sync_committee_targets
55
sync_committee_targets: \
6-
sync_committee_contract_abi \
76
sync_committee_types_stringer \
87
sync_committee_generate_mocks \
98
sync_committee_protobuf \
109
sync_committee_tracer_constants \
11-
$(root_sc)/generate_fee_updater_abi
10+
$(root_sc)/generate_rollup_contract_abi \
11+
$(root_sc)/generate_fee_updater_abi \
12+
$(root_sc)/compile_l2_bridge_state_getter_abi
1213

1314
.PHONY: $(root_sc)/compile_fee_updater_abi
1415
$(root_sc)/compile_fee_updater_abi:
@@ -18,13 +19,21 @@ $(root_sc)/compile_fee_updater_abi:
1819
$(root_sc)/generate_fee_updater_abi: $(root_sc)/compile_fee_updater_abi
1920
cd $(root_sc)/core/feeupdater && go run github.com/ethereum/go-ethereum/cmd/abigen --abi IFeeStorage.abi --pkg=feeupdater --out=./i_fee_storage_contract_abi_generated.go
2021

21-
.PHONY: sync_committee_contract_abi
22-
sync_committee_contract_abi: \
23-
$(root_sc)/core/rollupcontract/rollupcontract_abi_generated.go
22+
.PHONY: $(root_sc)/compile_rollup_contract_abi
23+
$(root_sc)/compile_rollup_contract_abi:
24+
solc $(root_contracts)/interfaces/INilRollup.sol --abi --overwrite -o $(root_sc)/core/rollupcontract --allow-paths .,$(root_contracts)/common/libraries --no-cbor-metadata --metadata-hash none --pretty-json
25+
26+
.PHONY: $(root_sc)/generate_rollup_contract_abi
27+
$(root_sc)/generate_rollup_contract_abi: $(root_sc)/compile_rollup_contract_abi
28+
cd $(root_sc)/core/rollupcontract && go run github.com/ethereum/go-ethereum/cmd/abigen --abi INilRollup.abi --pkg=rollupcontract --out=./i_rollup_contract_abi_generated.go
2429

25-
$(root_sc)/core/rollupcontract/rollupcontract_abi_generated.go: \
26-
$(root_sc)/core/rollupcontract/abi.json
27-
go generate $(root_sc)/core/rollupcontract/generate.go
30+
.PHONY: $(root_sc)/compile_l2_bridge_state_getter_abi
31+
$(root_sc)/compile_l2_bridge_state_getter_abi:
32+
solc $(root_contracts)/bridge/l2/interfaces/IL2BridgeStateGetter.sol --abi --overwrite -o $(root_sc)/core/bridgecontract --allow-paths .,$(root_contracts)/common/libraries --no-cbor-metadata --metadata-hash none --pretty-json
33+
34+
$(root_sc)/core/rollupcontract/wrapper_generated_mock.go: \
35+
$(root_sc)/generate_rollup_contract_abi
36+
cd $(root_sc)/core/rollupcontract && ../../internal/scripts/generate_mock.sh Wrapper
2837

2938
$(root_sc)/internal/l1client/eth_client_generated_mock.go:
3039
cd $(root_sc)/internal/l1client && bash ../../internal/scripts/generate_mock.sh EthClient
@@ -84,7 +93,7 @@ $(root_sc)/internal/api/task_state_change_handler_generated_mock.go: \
8493
go generate $(root_sc)/internal/api/task_state_change_handler.go
8594

8695
$(root_sc)/core/state_reset_launcher_generated_mock.go: \
87-
sync_committee_contract_abi \
96+
$(root_sc)/generate_rollup_contract_abi \
8897
$(root_sc)/core/task_state_change_handler.go
8998
go generate $(root_sc)/core/task_state_change_handler.go
9099

@@ -107,9 +116,9 @@ $(root_sc)/prover/tracer/storage_getter_setter_generated_mock.go: \
107116
go generate $(root_sc)/prover/tracer
108117

109118
$(root_sc)/core/rollupcontract/wrapper_generated_mock.go: \
110-
sync_committee_contract_abi \
119+
$(root_sc)/generate_rollup_contract_abi \
111120
$(root_sc)/core/rollupcontract/wrapper.go
112-
go generate $(root_sc)/core/rollupcontract/generate.go
121+
cd $(root_sc)/core/rollupcontract && bash ../../internal/scripts/generate_mock.sh Wrapper
113122

114123
$(root_sc)/core/feeupdater/contract_wrapper_generated_mock.go: \
115124
$(root_sc)/core/feeupdater/contract_wrapper.go \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package bridgecontract
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"math/big"
7+
8+
"github.com/NilFoundation/nil/nil/client"
9+
"github.com/NilFoundation/nil/nil/common/hexutil"
10+
"github.com/NilFoundation/nil/nil/internal/abi"
11+
"github.com/NilFoundation/nil/nil/internal/types"
12+
"github.com/NilFoundation/nil/nil/services/rpc/jsonrpc"
13+
"golang.org/x/sync/errgroup"
14+
)
15+
16+
type bytes32 = [32]uint8
17+
18+
type BridgeState struct {
19+
L2toL1Root *big.Int
20+
DepositNonce *big.Int
21+
L1MessageHash *big.Int
22+
}
23+
24+
type BridgeStateGetter interface {
25+
GetBridgeState(ctx context.Context, blockID any) (*BridgeState, error)
26+
}
27+
28+
type bridgeStateGetter struct {
29+
nilClient client.Client
30+
contractAddr types.Address
31+
abi *abi.ABI
32+
}
33+
34+
func NewBridgeStateGetter(
35+
nilClient client.Client,
36+
l2ContractAddr types.Address,
37+
) *bridgeStateGetter {
38+
return &bridgeStateGetter{
39+
nilClient: nilClient,
40+
contractAddr: l2ContractAddr,
41+
abi: GetL2BridgeStateGetterABI(),
42+
}
43+
}
44+
45+
func (b *bridgeStateGetter) GetBridgeState(ctx context.Context, blockID any) (*BridgeState, error) {
46+
eg, gCtx := errgroup.WithContext(ctx)
47+
48+
var l1MessageHash *big.Int
49+
eg.Go(func() error {
50+
ret, err := callContract[bytes32](gCtx, b.nilClient, blockID, b.contractAddr, b.abi, "l1MessageHash")
51+
if err != nil {
52+
return err
53+
}
54+
l1MessageHash = new(big.Int).SetBytes(ret[:])
55+
return nil
56+
})
57+
58+
var l2ToL1Root *big.Int
59+
eg.Go(func() error {
60+
ret, err := callContract[bytes32](gCtx, b.nilClient, blockID, b.contractAddr, b.abi, "getL2ToL1Root")
61+
if err != nil {
62+
return err
63+
}
64+
l2ToL1Root = new(big.Int).SetBytes(ret[:])
65+
return nil
66+
})
67+
68+
var depositNonce *big.Int
69+
eg.Go(func() error {
70+
ret, err := callContract[*big.Int](gCtx, b.nilClient, blockID, b.contractAddr, b.abi, "getLatestDepositNonce")
71+
if err != nil {
72+
return err
73+
}
74+
depositNonce = ret
75+
return nil
76+
})
77+
78+
if err := eg.Wait(); err != nil {
79+
return nil, err
80+
}
81+
82+
ret := &BridgeState{
83+
L2toL1Root: l2ToL1Root,
84+
DepositNonce: depositNonce,
85+
L1MessageHash: l1MessageHash,
86+
}
87+
return ret, nil
88+
}
89+
90+
func callContract[Ret any](
91+
ctx context.Context,
92+
c client.Client,
93+
blockID any,
94+
addr types.Address,
95+
abi *abi.ABI,
96+
method string,
97+
args ...any,
98+
) (Ret, error) {
99+
var ret Ret
100+
calldata, err := abi.Pack(method, args...)
101+
if err != nil {
102+
return ret, err
103+
}
104+
105+
callArgs := &jsonrpc.CallArgs{
106+
Data: (*hexutil.Bytes)(&calldata),
107+
To: addr,
108+
Fee: types.NewFeePackFromGas(100_000), // TODO(oclaw) which value to use here?
109+
}
110+
111+
callRes, err := c.Call(ctx, callArgs, blockID, nil)
112+
if err != nil {
113+
return ret, err
114+
}
115+
116+
res, err := abi.Unpack(method, callRes.Data)
117+
if err != nil {
118+
return ret, err
119+
}
120+
121+
if len(res) != 1 {
122+
return ret, fmt.Errorf("expected single return value, got %d", len(res))
123+
}
124+
125+
var ok bool
126+
ret, ok = res[0].(Ret)
127+
if !ok {
128+
return ret, fmt.Errorf("type mismatch for return value of method %s: expected %T got %T", method, ret, res[0])
129+
}
130+
131+
return ret, nil
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package bridgecontract
2+
3+
import (
4+
"bytes"
5+
_ "embed"
6+
7+
"github.com/NilFoundation/nil/nil/common/check"
8+
"github.com/NilFoundation/nil/nil/internal/abi"
9+
)
10+
11+
//go:embed IL2BridgeStateGetter.abi
12+
var l2BridgeStateGetterContractABIData []byte
13+
14+
var l2BridgeStateGetterContractABI *abi.ABI
15+
16+
func init() {
17+
abi, err := abi.JSON(bytes.NewReader(l2BridgeStateGetterContractABIData))
18+
check.PanicIfErr(err)
19+
if err != nil {
20+
panic(err)
21+
}
22+
l2BridgeStateGetterContractABI = &abi
23+
}
24+
25+
func GetL2BridgeStateGetterABI() *abi.ABI {
26+
return l2BridgeStateGetterContractABI
27+
}

nil/services/synccommittee/core/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Config struct {
2020
ContractWrapperConfig rollupcontract.WrapperConfig `yaml:",inline"`
2121
L1FeeUpdateConfig feeupdater.Config `yaml:",inline"`
2222
L1FeeUpdateContractConfig feeupdater.ContractWrapperConfig `yaml:",inline"`
23+
L2BridgeMessegerAdddress string `yaml:"l2BridgeMessegerAdddress"`
2324
Telemetry *telemetry.Config `yaml:",inline"`
2425
}
2526

nil/services/synccommittee/core/proposer.go

+18-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/NilFoundation/nil/nil/common"
1010
"github.com/NilFoundation/nil/nil/common/concurrent"
1111
"github.com/NilFoundation/nil/nil/common/logging"
12+
"github.com/NilFoundation/nil/nil/services/synccommittee/core/bridgecontract"
1213
"github.com/NilFoundation/nil/nil/services/synccommittee/core/reset"
1314
"github.com/NilFoundation/nil/nil/services/synccommittee/core/rollupcontract"
1415
"github.com/NilFoundation/nil/nil/services/synccommittee/internal/log"
@@ -35,6 +36,7 @@ type proposer struct {
3536

3637
storage ProposerStorage
3738
resetter *reset.StateResetLauncher
39+
bridgeStateGetter bridgecontract.BridgeStateGetter
3840
rollupContractWrapper rollupcontract.Wrapper
3941
metrics ProposerMetrics
4042
logger logging.Logger
@@ -56,13 +58,15 @@ func NewDefaultProposerConfig() ProposerConfig {
5658
func NewProposer(
5759
config ProposerConfig,
5860
storage ProposerStorage,
61+
bridgeStateGetter bridgecontract.BridgeStateGetter,
5962
contractWrapper rollupcontract.Wrapper,
6063
resetter *reset.StateResetLauncher,
6164
metrics ProposerMetrics,
6265
logger logging.Logger,
6366
) (*proposer, error) {
6467
p := &proposer{
6568
storage: storage,
69+
bridgeStateGetter: bridgeStateGetter,
6670
rollupContractWrapper: contractWrapper,
6771
resetter: resetter,
6872
metrics: metrics,
@@ -110,14 +114,24 @@ func (p *proposer) updateState(
110114
ctx context.Context,
111115
proposalData *scTypes.ProposalData,
112116
) error {
113-
// TODO: populate with actual data
117+
// NOTE(oclaw) current impl assumes that L2BridgeMessenger is deployed at the main shard
118+
// if it is not - we need to expilicitly set shard id and use latest block ref from it
119+
lastestMainBlockRef := proposalData.NewProvedStateRoot
120+
if lastestMainBlockRef == common.EmptyHash {
121+
return errors.New("latest main block ref is empty")
122+
}
123+
124+
bridgeData, err := p.bridgeStateGetter.GetBridgeState(ctx, lastestMainBlockRef)
125+
if err != nil {
126+
return fmt.Errorf("failed to get bridge state: %w", err)
127+
}
114128

115129
updateStateData := scTypes.NewUpdateStateData(
116130
proposalData,
117131
[]byte{0x0A, 0x0B, 0x0C},
118-
common.EmptyHash,
119-
0,
120-
common.EmptyHash,
132+
common.BigToHash(bridgeData.L2toL1Root),
133+
common.BigToHash(bridgeData.L1MessageHash),
134+
bridgeData.DepositNonce,
121135
)
122136

123137
log.NewStateUpdateEvent(p.logger, zerolog.InfoLevel, updateStateData).Msg("calling UpdateState L1 method")

nil/services/synccommittee/core/proposer_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/NilFoundation/nil/nil/internal/db"
1313
"github.com/NilFoundation/nil/nil/internal/types"
1414
"github.com/NilFoundation/nil/nil/services/rpc/jsonrpc"
15+
"github.com/NilFoundation/nil/nil/services/synccommittee/core/bridgecontract"
1516
"github.com/NilFoundation/nil/nil/services/synccommittee/core/fetching"
1617
"github.com/NilFoundation/nil/nil/services/synccommittee/core/reset"
1718
"github.com/NilFoundation/nil/nil/services/synccommittee/core/rollupcontract"
@@ -111,6 +112,8 @@ func (s *ProposerTestSuite) SetupSuite() {
111112
)
112113
s.Require().NoError(err)
113114

115+
l2BridgeMessengerContractAddr := types.HexToAddress("0x1234")
116+
114117
s.rpcClientMock = &client.ClientMock{
115118
GetBlockFunc: func(_ context.Context, shardId types.ShardId, blockId any, _ bool) (*jsonrpc.RPCBlock, error) {
116119
strId, ok := blockId.(string)
@@ -126,15 +129,30 @@ func (s *ProposerTestSuite) SetupSuite() {
126129
block.Hash = blockHash
127130
return block, nil
128131
},
132+
CallFunc: func(
133+
ctx context.Context, args *jsonrpc.CallArgs, blockId any, stateOverride *jsonrpc.StateOverrides,
134+
) (*jsonrpc.CallRes, error) {
135+
switch {
136+
case args.To.Equal(l2BridgeMessengerContractAddr):
137+
ret := types.NewUint256(123).Bytes32()
138+
return &jsonrpc.CallRes{
139+
Data: ret[:],
140+
}, nil
141+
default:
142+
return nil, fmt.Errorf("unexpected contract address: %s", args.To)
143+
}
144+
},
129145
}
130146

131147
fetcher := fetching.NewFetcher(s.rpcClientMock, logger)
132148
l1Syncer := syncer.NewStateRootSyncer(fetcher, contractWrapper, s.storage, logger, syncer.NewDefaultConfig())
133149
resetLauncher := reset.NewResetLauncher(s.storage, l1Syncer, nil, logger)
150+
bridgeStateGetter := bridgecontract.NewBridgeStateGetter(s.rpcClientMock, l2BridgeMessengerContractAddr)
134151

135152
s.proposer, err = NewProposer(
136153
s.params,
137154
s.storage,
155+
bridgeStateGetter,
138156
contractWrapper,
139157
resetLauncher,
140158
metricsHandler,

0 commit comments

Comments
 (0)