@@ -2,7 +2,12 @@ package system_contract
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
6
+ "github.com/scroll-tech/go-ethereum"
7
+ "github.com/scroll-tech/go-ethereum/accounts/abi"
8
+ "github.com/scroll-tech/go-ethereum/ethclient"
5
9
"math/big"
10
+ "strings"
6
11
"sync"
7
12
"time"
8
13
@@ -26,8 +31,7 @@ type SystemContract struct {
26
31
config * params.SystemContractConfig // Consensus engine configuration parameters
27
32
client sync_service.EthClient
28
33
29
- signerAddressL1 common.Address // Address of the signer stored in L1 System Contract
30
- signerAddressesL1 []SignerAddressL1
34
+ signerAddressesL1 []SignerAddressL1 // Addresses of the signer stored in L1 System Contract
31
35
32
36
signer common.Address // Ethereum address of the signing key
33
37
signFn SignerFn // Signer function to authorize hashes with
@@ -40,16 +44,10 @@ type SystemContract struct {
40
44
// New creates a SystemContract consensus engine with the initial
41
45
// signers set to the ones provided by the user.
42
46
func New (ctx context.Context , config * params.SystemContractConfig , client sync_service.EthClient ) * SystemContract {
43
- blockNumber := big .NewInt (- 1 ) // todo: get block number from L1BlocksContract (l1 block hash relay) or other source (depending on exact design)
44
47
ctx , cancel := context .WithCancel (ctx )
45
- address , err := client .StorageAt (ctx , config .SystemContractAddress , config .SystemContractSlot , blockNumber )
46
- if err != nil {
47
- log .Error ("failed to get signer address from L1 System Contract" , "err" , err )
48
- }
49
48
systemContract := & SystemContract {
50
- config : config ,
51
- client : client ,
52
- signerAddressL1 : common .BytesToAddress (address ),
49
+ config : config ,
50
+ client : client ,
53
51
54
52
ctx : ctx ,
55
53
cancel : cancel ,
@@ -58,6 +56,76 @@ func New(ctx context.Context, config *params.SystemContractConfig, client sync_s
58
56
return systemContract
59
57
}
60
58
59
+ // Hardcoded ABI snippet for getAllTransitions():
60
+ //
61
+ // function getAllTransitions() external view returns (uint64[] memory, address[] memory);
62
+ //
63
+ // We only need what's necessary to encode/decode "getAllTransitions".
64
+ const getAllTransitionsABI = `[
65
+ {
66
+ "inputs": [],
67
+ "name": "getAllTransitions",
68
+ "outputs": [
69
+ {"internalType": "uint64[]", "type": "uint64[]"},
70
+ {"internalType": "address[]","type": "address[]"}
71
+ ],
72
+ "stateMutability": "view",
73
+ "type": "function"
74
+ }
75
+ ]`
76
+
77
+ // fetchAllSigners calls getAllTransitions() on the contract, decodes the results,
78
+ // and returns them as a slice of [StartBlock, Signer].
79
+ func (s * SystemContract ) fetchAllSigners (blockNum * big.Int ) ([]SignerAddressL1 , error ) {
80
+ // Parse the ABI so we can encode and decode calls
81
+ parsedABI , err := abi .JSON (strings .NewReader (getAllTransitionsABI ))
82
+ if err != nil {
83
+ return nil , fmt .Errorf ("parse ABI error: %w" , err )
84
+ }
85
+
86
+ // Pack the function call data
87
+ packed , err := parsedABI .Pack ("getAllTransitions" )
88
+ if err != nil {
89
+ return nil , fmt .Errorf ("ABI pack error: %w" , err )
90
+ }
91
+
92
+ // Prepare the call
93
+ msg := ethereum.CallMsg {
94
+ To : & s .config .SystemContractAddress , // The address of your SystemSignerRegistry contract
95
+ Data : packed ,
96
+ }
97
+
98
+ // Perform the call via the ethclient interface (need to cast)
99
+ output , err := s .client .(* ethclient.Client ).CallContract (s .ctx , msg , blockNum )
100
+ if err != nil {
101
+ return nil , fmt .Errorf ("CallContract error: %w" , err )
102
+ }
103
+ // Decode the (uint64[] memory, address[] memory) from output
104
+ var ret struct {
105
+ Blocks []* big.Int
106
+ Signers []common.Address
107
+ }
108
+ err = parsedABI .UnpackIntoInterface (& ret , "getAllTransitions" , output )
109
+ if err != nil {
110
+ return nil , fmt .Errorf ("unpack error: %w" , err )
111
+ }
112
+
113
+ if len (ret .Blocks ) != len (ret .Signers ) {
114
+ return nil , fmt .Errorf ("mismatched array lengths blocks=%d signers=%d" ,
115
+ len (ret .Blocks ), len (ret .Signers ))
116
+ }
117
+
118
+ // Convert them into []SignerAddressL1
119
+ result := make ([]SignerAddressL1 , 0 , len (ret .Blocks ))
120
+ for i := range ret .Blocks {
121
+ result = append (result , SignerAddressL1 {
122
+ StartBlock : ret .Blocks [i ].Uint64 (),
123
+ Signer : ret .Signers [i ],
124
+ })
125
+ }
126
+ return result , nil
127
+ }
128
+
61
129
// Authorize injects a private key into the consensus engine to mint new blocks
62
130
// with.
63
131
func (s * SystemContract ) Authorize (signer common.Address , signFn SignerFn ) {
@@ -71,6 +139,14 @@ func (s *SystemContract) Authorize(signer common.Address, signFn SignerFn) {
71
139
func (s * SystemContract ) Start () {
72
140
log .Info ("starting SystemContract" )
73
141
go func () {
142
+ s .lock .Lock ()
143
+ signers , err := s .fetchAllSigners (nil ) // nil -> latest state
144
+ if err != nil {
145
+ log .Error ("failed to get signer address from L1 System Contract" , "err" , err )
146
+ }
147
+ s .signerAddressesL1 = signers
148
+ s .lock .Unlock ()
149
+
74
150
syncTicker := time .NewTicker (defaultSyncInterval )
75
151
defer syncTicker .Stop ()
76
152
for {
@@ -83,14 +159,12 @@ func (s *SystemContract) Start() {
83
159
case <- s .ctx .Done ():
84
160
return
85
161
case <- syncTicker .C :
86
- //TODO here
87
- blockNumber := big .NewInt (- 1 ) // todo: get block number from L1BlocksContract (l1 block hash relay) or other source (depending on exact design)
88
- address , err := s .client .StorageAt (s .ctx , s .config .SystemContractAddress , s .config .SystemContractSlot , blockNumber )
162
+ s .lock .Lock ()
163
+ signers , err := s .fetchAllSigners (nil ) // nil -> latest state
89
164
if err != nil {
90
165
log .Error ("failed to get signer address from L1 System Contract" , "err" , err )
91
166
}
92
- s .lock .Lock ()
93
- s .signerAddressL1 = common .BytesToAddress (address )
167
+ s .signerAddressesL1 = signers
94
168
s .lock .Unlock ()
95
169
}
96
170
}
0 commit comments