Skip to content

Commit 8b0475c

Browse files
committed
Implement retrieval of latest SignerAddresses from L1
1 parent f9a9348 commit 8b0475c

File tree

1 file changed

+89
-15
lines changed

1 file changed

+89
-15
lines changed

consensus/system_contract/system_contract.go

+89-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ package system_contract
22

33
import (
44
"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"
59
"math/big"
10+
"strings"
611
"sync"
712
"time"
813

@@ -26,8 +31,7 @@ type SystemContract struct {
2631
config *params.SystemContractConfig // Consensus engine configuration parameters
2732
client sync_service.EthClient
2833

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
3135

3236
signer common.Address // Ethereum address of the signing key
3337
signFn SignerFn // Signer function to authorize hashes with
@@ -40,16 +44,10 @@ type SystemContract struct {
4044
// New creates a SystemContract consensus engine with the initial
4145
// signers set to the ones provided by the user.
4246
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)
4447
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-
}
4948
systemContract := &SystemContract{
50-
config: config,
51-
client: client,
52-
signerAddressL1: common.BytesToAddress(address),
49+
config: config,
50+
client: client,
5351

5452
ctx: ctx,
5553
cancel: cancel,
@@ -58,6 +56,76 @@ func New(ctx context.Context, config *params.SystemContractConfig, client sync_s
5856
return systemContract
5957
}
6058

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+
61129
// Authorize injects a private key into the consensus engine to mint new blocks
62130
// with.
63131
func (s *SystemContract) Authorize(signer common.Address, signFn SignerFn) {
@@ -71,6 +139,14 @@ func (s *SystemContract) Authorize(signer common.Address, signFn SignerFn) {
71139
func (s *SystemContract) Start() {
72140
log.Info("starting SystemContract")
73141
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+
74150
syncTicker := time.NewTicker(defaultSyncInterval)
75151
defer syncTicker.Stop()
76152
for {
@@ -83,14 +159,12 @@ func (s *SystemContract) Start() {
83159
case <-s.ctx.Done():
84160
return
85161
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
89164
if err != nil {
90165
log.Error("failed to get signer address from L1 System Contract", "err", err)
91166
}
92-
s.lock.Lock()
93-
s.signerAddressL1 = common.BytesToAddress(address)
167+
s.signerAddressesL1 = signers
94168
s.lock.Unlock()
95169
}
96170
}

0 commit comments

Comments
 (0)