Skip to content

Commit c6285e6

Browse files
rjl493456442karalabe
authored andcommitted
les/checkpointoracle: move oracle into its own package (#20508)
* les: move the checkpoint oracle into its own package It's first step of refactor LES package. LES package basically can be divided into LES client and LES server. However both sides will use checkpoint package for status retrieval and verification. So this PR moves checkpoint oracle into a separate package * les: address comments
1 parent 35f95ae commit c6285e6

File tree

11 files changed

+71
-53
lines changed

11 files changed

+71
-53
lines changed

contracts/checkpointoracle/oracle.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ import (
2929
"github.com/ethereum/go-ethereum/core/types"
3030
)
3131

32-
// CheckpointOracle is a Go wrapper around an on-chain light client checkpoint oracle.
32+
// CheckpointOracle is a Go wrapper around an on-chain checkpoint oracle contract.
3333
type CheckpointOracle struct {
34+
address common.Address
3435
contract *contract.CheckpointOracle
3536
}
3637

@@ -40,7 +41,12 @@ func NewCheckpointOracle(contractAddr common.Address, backend bind.ContractBacke
4041
if err != nil {
4142
return nil, err
4243
}
43-
return &CheckpointOracle{contract: c}, nil
44+
return &CheckpointOracle{address: contractAddr, contract: c}, nil
45+
}
46+
47+
// ContractAddr returns the address of contract.
48+
func (oracle *CheckpointOracle) ContractAddr() common.Address {
49+
return oracle.address
4450
}
4551

4652
// Contract returns the underlying contract instance.

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo
101101
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
102102
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
103103
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
104+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
104105
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
105106
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
106107
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=

les/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,5 +350,5 @@ func (api *PrivateLightAPI) GetCheckpointContractAddress() (string, error) {
350350
if api.backend.oracle == nil {
351351
return "", errNotActivated
352352
}
353-
return api.backend.oracle.config.Address.Hex(), nil
353+
return api.backend.oracle.Contract().ContractAddr().Hex(), nil
354354
}

les/checkpointoracle.go renamed to les/checkpointoracle/oracle.go

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package les
17+
// Package checkpointoracle is a wrapper of checkpoint oracle contract with
18+
// additional rules defined. This package can be used both in LES client or
19+
// server side for offering oracle related APIs.
20+
package checkpointoracle
1821

1922
import (
2023
"encoding/binary"
@@ -28,19 +31,19 @@ import (
2831
"github.com/ethereum/go-ethereum/params"
2932
)
3033

31-
// checkpointOracle is responsible for offering the latest stable checkpoint
32-
// generated and announced by the contract admins on-chain. The checkpoint is
33-
// verified by clients locally during the checkpoint syncing.
34-
type checkpointOracle struct {
34+
// CheckpointOracle is responsible for offering the latest stable checkpoint
35+
// generated and announced by the contract admins on-chain. The checkpoint can
36+
// be verified by clients locally during the checkpoint syncing.
37+
type CheckpointOracle struct {
3538
config *params.CheckpointOracleConfig
3639
contract *checkpointoracle.CheckpointOracle
3740

3841
running int32 // Flag whether the contract backend is set or not
3942
getLocal func(uint64) params.TrustedCheckpoint // Function used to retrieve local checkpoint
4043
}
4144

42-
// newCheckpointOracle returns a checkpoint registrar handler.
43-
func newCheckpointOracle(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *checkpointOracle {
45+
// New creates a checkpoint oracle handler with given configs and callback.
46+
func New(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *CheckpointOracle {
4447
if config == nil {
4548
log.Info("Checkpoint registrar is not enabled")
4649
return nil
@@ -51,61 +54,65 @@ func newCheckpointOracle(config *params.CheckpointOracleConfig, getLocal func(ui
5154
}
5255
log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)
5356

54-
return &checkpointOracle{
57+
return &CheckpointOracle{
5558
config: config,
5659
getLocal: getLocal,
5760
}
5861
}
5962

60-
// start binds the registrar contract and start listening to the
61-
// newCheckpointEvent for the server side.
62-
func (reg *checkpointOracle) start(backend bind.ContractBackend) {
63-
contract, err := checkpointoracle.NewCheckpointOracle(reg.config.Address, backend)
63+
// Start binds the contract backend, initializes the oracle instance
64+
// and marks the status as available.
65+
func (oracle *CheckpointOracle) Start(backend bind.ContractBackend) {
66+
contract, err := checkpointoracle.NewCheckpointOracle(oracle.config.Address, backend)
6467
if err != nil {
6568
log.Error("Oracle contract binding failed", "err", err)
6669
return
6770
}
68-
if !atomic.CompareAndSwapInt32(&reg.running, 0, 1) {
71+
if !atomic.CompareAndSwapInt32(&oracle.running, 0, 1) {
6972
log.Error("Already bound and listening to registrar")
7073
return
7174
}
72-
reg.contract = contract
75+
oracle.contract = contract
7376
}
7477

75-
// isRunning returns an indicator whether the registrar is running.
76-
func (reg *checkpointOracle) isRunning() bool {
77-
return atomic.LoadInt32(&reg.running) == 1
78+
// IsRunning returns an indicator whether the oracle is running.
79+
func (oracle *CheckpointOracle) IsRunning() bool {
80+
return atomic.LoadInt32(&oracle.running) == 1
7881
}
7982

80-
// stableCheckpoint returns the stable checkpoint which was generated by local
83+
// Contract returns the underlying raw checkpoint oracle contract.
84+
func (oracle *CheckpointOracle) Contract() *checkpointoracle.CheckpointOracle {
85+
return oracle.contract
86+
}
87+
88+
// StableCheckpoint returns the stable checkpoint which was generated by local
8189
// indexers and announced by trusted signers.
82-
func (reg *checkpointOracle) stableCheckpoint() (*params.TrustedCheckpoint, uint64) {
90+
func (oracle *CheckpointOracle) StableCheckpoint() (*params.TrustedCheckpoint, uint64) {
8391
// Retrieve the latest checkpoint from the contract, abort if empty
84-
latest, hash, height, err := reg.contract.Contract().GetLatestCheckpoint(nil)
92+
latest, hash, height, err := oracle.contract.Contract().GetLatestCheckpoint(nil)
8593
if err != nil || (latest == 0 && hash == [32]byte{}) {
8694
return nil, 0
8795
}
88-
local := reg.getLocal(latest)
96+
local := oracle.getLocal(latest)
8997

9098
// The following scenarios may occur:
9199
//
92100
// * local node is out of sync so that it doesn't have the
93101
// checkpoint which registered in the contract.
94102
// * local checkpoint doesn't match with the registered one.
95103
//
96-
// In both cases, server won't send the **stable** checkpoint
97-
// to the client(no worry, client can use hardcoded one instead).
98-
if local.HashEqual(common.Hash(hash)) {
104+
// In both cases, no stable checkpoint will be returned.
105+
if local.HashEqual(hash) {
99106
return &local, height.Uint64()
100107
}
101108
return nil, 0
102109
}
103110

104-
// verifySigners recovers the signer addresses according to the signature and
111+
// VerifySigners recovers the signer addresses according to the signature and
105112
// checks whether there are enough approvals to finalize the checkpoint.
106-
func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
113+
func (oracle *CheckpointOracle) VerifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
107114
// Short circuit if the given signatures doesn't reach the threshold.
108-
if len(signatures) < int(reg.config.Threshold) {
115+
if len(signatures) < int(oracle.config.Threshold) {
109116
return false, nil
110117
}
111118
var (
@@ -128,7 +135,7 @@ func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatur
128135
// hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root)
129136
buf := make([]byte, 8)
130137
binary.BigEndian.PutUint64(buf, index)
131-
data := append([]byte{0x19, 0x00}, append(reg.config.Address.Bytes(), append(buf, hash[:]...)...)...)
138+
data := append([]byte{0x19, 0x00}, append(oracle.config.Address.Bytes(), append(buf, hash[:]...)...)...)
132139
signatures[i][64] -= 27 // Transform V from 27/28 to 0/1 according to the yellow paper for verification.
133140
pubkey, err := crypto.Ecrecover(crypto.Keccak256(data), signatures[i])
134141
if err != nil {
@@ -139,14 +146,14 @@ func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatur
139146
if _, exist := checked[signer]; exist {
140147
continue
141148
}
142-
for _, s := range reg.config.Signers {
149+
for _, s := range oracle.config.Signers {
143150
if s == signer {
144151
signers = append(signers, signer)
145152
checked[signer] = struct{}{}
146153
}
147154
}
148155
}
149-
threshold := reg.config.Threshold
156+
threshold := oracle.config.Threshold
150157
if uint64(len(signers)) < threshold {
151158
log.Warn("Not enough signers to approve checkpoint", "signers", len(signers), "threshold", threshold)
152159
return false, nil

les/client.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/ethereum/go-ethereum/eth/gasprice"
3737
"github.com/ethereum/go-ethereum/event"
3838
"github.com/ethereum/go-ethereum/internal/ethapi"
39+
"github.com/ethereum/go-ethereum/les/checkpointoracle"
3940
"github.com/ethereum/go-ethereum/light"
4041
"github.com/ethereum/go-ethereum/log"
4142
"github.com/ethereum/go-ethereum/node"
@@ -123,7 +124,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
123124
if oracle == nil {
124125
oracle = params.CheckpointOracles[genesisHash]
125126
}
126-
leth.oracle = newCheckpointOracle(oracle, leth.localCheckpoint)
127+
leth.oracle = checkpointoracle.New(oracle, leth.localCheckpoint)
127128

128129
// Note: AddChildIndexer starts the update process for the child
129130
leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
@@ -275,5 +276,5 @@ func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) {
275276
if s.oracle == nil {
276277
return
277278
}
278-
s.oracle.start(backend)
279+
s.oracle.Start(backend)
279280
}

les/commons.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/ethereum/go-ethereum/core/types"
2828
"github.com/ethereum/go-ethereum/eth"
2929
"github.com/ethereum/go-ethereum/ethdb"
30+
"github.com/ethereum/go-ethereum/les/checkpointoracle"
3031
"github.com/ethereum/go-ethereum/light"
3132
"github.com/ethereum/go-ethereum/p2p"
3233
"github.com/ethereum/go-ethereum/p2p/discv5"
@@ -63,7 +64,7 @@ type lesCommons struct {
6364
peers *peerSet
6465
chainReader chainReader
6566
chtIndexer, bloomTrieIndexer *core.ChainIndexer
66-
oracle *checkpointOracle
67+
oracle *checkpointoracle.CheckpointOracle
6768

6869
closeCh chan struct{}
6970
wg sync.WaitGroup

les/peer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,8 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
616616

617617
// Add advertised checkpoint and register block height which
618618
// client can verify the checkpoint validity.
619-
if server.oracle != nil && server.oracle.isRunning() {
620-
cp, height := server.oracle.stableCheckpoint()
619+
if server.oracle != nil && server.oracle.IsRunning() {
620+
cp, height := server.oracle.StableCheckpoint()
621621
if cp != nil {
622622
send = send.add("checkpoint/value", cp)
623623
send = send.add("checkpoint/registerHeight", height)

les/server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/ethereum/go-ethereum/common/mclock"
2525
"github.com/ethereum/go-ethereum/core"
2626
"github.com/ethereum/go-ethereum/eth"
27+
"github.com/ethereum/go-ethereum/les/checkpointoracle"
2728
"github.com/ethereum/go-ethereum/les/flowcontrol"
2829
"github.com/ethereum/go-ethereum/light"
2930
"github.com/ethereum/go-ethereum/log"
@@ -96,7 +97,7 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
9697
if oracle == nil {
9798
oracle = params.CheckpointOracles[e.BlockChain().Genesis().Hash()]
9899
}
99-
srv.oracle = newCheckpointOracle(oracle, srv.localCheckpoint)
100+
srv.oracle = checkpointoracle.New(oracle, srv.localCheckpoint)
100101

101102
// Initialize server capacity management fields.
102103
srv.defParams = flowcontrol.ServerParams{
@@ -216,7 +217,7 @@ func (s *LesServer) SetContractBackend(backend bind.ContractBackend) {
216217
if s.oracle == nil {
217218
return
218219
}
219-
s.oracle.start(backend)
220+
s.oracle.Start(backend)
220221
}
221222

222223
// capacityManagement starts an event handler loop that updates the recharge curve of

les/sync.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (h *clientHandler) validateCheckpoint(peer *peer) error {
6666
if err != nil {
6767
return err
6868
}
69-
events := h.backend.oracle.contract.LookupCheckpointEvents(logs, cp.SectionIndex, cp.Hash())
69+
events := h.backend.oracle.Contract().LookupCheckpointEvents(logs, cp.SectionIndex, cp.Hash())
7070
if len(events) == 0 {
7171
return errInvalidCheckpoint
7272
}
@@ -78,7 +78,7 @@ func (h *clientHandler) validateCheckpoint(peer *peer) error {
7878
for _, event := range events {
7979
signatures = append(signatures, append(event.R[:], append(event.S[:], event.V)...))
8080
}
81-
valid, signers := h.backend.oracle.verifySigners(index, hash, signatures)
81+
valid, signers := h.backend.oracle.VerifySigners(index, hash, signatures)
8282
if !valid {
8383
return errInvalidCheckpoint
8484
}
@@ -134,7 +134,7 @@ func (h *clientHandler) synchronise(peer *peer) {
134134
case hardcoded:
135135
mode = legacyCheckpointSync
136136
log.Debug("Disable checkpoint syncing", "reason", "checkpoint is hardcoded")
137-
case h.backend.oracle == nil || !h.backend.oracle.isRunning():
137+
case h.backend.oracle == nil || !h.backend.oracle.IsRunning():
138138
if h.checkpoint == nil {
139139
mode = lightSync // Downgrade to light sync unfortunately.
140140
} else {

les/sync_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) {
8080
data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...)
8181
sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey)
8282
sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
83-
if _, err := server.handler.server.oracle.contract.RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
83+
if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
8484
t.Error("register checkpoint failed", err)
8585
}
8686
server.backend.Commit()
8787

8888
// Wait for the checkpoint registration
8989
for {
90-
_, hash, _, err := server.handler.server.oracle.contract.Contract().GetLatestCheckpoint(nil)
90+
_, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil)
9191
if err != nil || hash == [32]byte{} {
9292
time.Sleep(10 * time.Millisecond)
9393
continue
@@ -164,14 +164,14 @@ func testMissOracleBackend(t *testing.T, hasCheckpoint bool) {
164164
data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...)
165165
sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey)
166166
sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
167-
if _, err := server.handler.server.oracle.contract.RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
167+
if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
168168
t.Error("register checkpoint failed", err)
169169
}
170170
server.backend.Commit()
171171

172172
// Wait for the checkpoint registration
173173
for {
174-
_, hash, _, err := server.handler.server.oracle.contract.Contract().GetLatestCheckpoint(nil)
174+
_, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil)
175175
if err != nil || hash == [32]byte{} {
176176
time.Sleep(100 * time.Millisecond)
177177
continue

0 commit comments

Comments
 (0)