Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions contracts/checkpointoracle/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)

// CheckpointOracle is a Go wrapper around an on-chain light client checkpoint oracle.
// CheckpointOracle is a Go wrapper around an on-chain checkpoint oracle contract.
type CheckpointOracle struct {
address common.Address
contract *contract.CheckpointOracle
}

Expand All @@ -40,7 +41,12 @@ func NewCheckpointOracle(contractAddr common.Address, backend bind.ContractBacke
if err != nil {
return nil, err
}
return &CheckpointOracle{contract: c}, nil
return &CheckpointOracle{address: contractAddr, contract: c}, nil
}

// ContractAddr returns the address of contract.
func (oracle *CheckpointOracle) ContractAddr() common.Address {
return oracle.address
}

// Contract returns the underlying contract instance.
Expand Down
3 changes: 2 additions & 1 deletion ethstats/ethstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
lesproto "github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
Expand Down Expand Up @@ -378,7 +379,7 @@ func (s *Service) login(conn *websocket.Conn) error {
protocol = fmt.Sprintf("eth/%d", eth.ProtocolVersions[0])
} else {
network = fmt.Sprintf("%d", infos.Protocols["les"].(*les.NodeInfo).Network)
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0])
protocol = fmt.Sprintf("les/%d", lesproto.ClientProtocolVersions[0])
}
auth := &authMsg{
ID: s.node,
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
Expand Down
2 changes: 1 addition & 1 deletion les/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,5 +350,5 @@ func (api *PrivateLightAPI) GetCheckpointContractAddress() (string, error) {
if api.backend.oracle == nil {
return "", errNotActivated
}
return api.backend.oracle.config.Address.Hex(), nil
return api.backend.oracle.Contract().ContractAddr().Hex(), nil
}
33 changes: 22 additions & 11 deletions les/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/les/utilities"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
Expand Down Expand Up @@ -118,9 +120,9 @@ func (b *benchmarkProofsOrCode) request(peer *peer, index int) error {
key := make([]byte, 32)
rand.Read(key)
if b.code {
return peer.RequestCode(0, 0, []CodeReq{{BHash: b.headHash, AccKey: key}})
return peer.RequestCode(0, 0, []protocol.CodeRequest{{BlockHash: b.headHash, Account: key}})
} else {
return peer.RequestProofs(0, 0, []ProofReq{{BHash: b.headHash, Key: key}})
return peer.RequestProofs(0, 0, []protocol.TrieProofRequest{{BlockHash: b.headHash, Key: key}})
}
}

Expand All @@ -145,21 +147,30 @@ func (b *benchmarkHelperTrie) init(h *serverHandler, count int) error {
}

func (b *benchmarkHelperTrie) request(peer *peer, index int) error {
reqs := make([]HelperTrieReq, b.reqCount)
reqs := make([]protocol.HelperTrieRequest, b.reqCount)

if b.bloom {
bitIdx := uint16(rand.Intn(2048))
for i := range reqs {
key := make([]byte, 10)
binary.BigEndian.PutUint16(key[:2], bitIdx)
binary.BigEndian.PutUint64(key[2:], uint64(rand.Int63n(int64(b.sectionCount))))
reqs[i] = HelperTrieReq{Type: htBloomBits, TrieIdx: b.sectionCount - 1, Key: key}
reqs[i] = protocol.HelperTrieRequest{
Type: protocol.HelperTrieBloomTrie,
TrieIndex: b.sectionCount - 1,
Key: key,
}
}
} else {
for i := range reqs {
key := make([]byte, 8)
binary.BigEndian.PutUint64(key[:], uint64(rand.Int63n(int64(b.headNum))))
reqs[i] = HelperTrieReq{Type: htCanonical, TrieIdx: b.sectionCount - 1, Key: key, AuxReq: auxHeader}
reqs[i] = protocol.HelperTrieRequest{
Type: protocol.HelperTrieCHT,
TrieIndex: b.sectionCount - 1,
Key: key,
AuxType: protocol.AuxHeader,
}
}
}

Expand Down Expand Up @@ -283,13 +294,13 @@ func (h *serverHandler) measure(setup *benchmarkSetup, count int) error {
var id enode.ID
rand.Read(id[:])

clientPeer := newPeer(lpv2, NetworkId, false, p2p.NewPeer(id, "client", nil), clientMeteredPipe)
serverPeer := newPeer(lpv2, NetworkId, false, p2p.NewPeer(id, "server", nil), serverMeteredPipe)
serverPeer.sendQueue = newExecQueue(count)
clientPeer := newPeer(protocol.Lpv2, protocol.NetworkId, false, p2p.NewPeer(id, "client", nil), clientMeteredPipe)
serverPeer := newPeer(protocol.Lpv2, protocol.NetworkId, false, p2p.NewPeer(id, "server", nil), serverMeteredPipe)
serverPeer.sendQueue = utilities.NewExecQueue(count)
serverPeer.announceType = announceTypeNone
serverPeer.fcCosts = make(requestCostTable)
c := &requestCosts{}
for code := range requests {
serverPeer.fcCosts = make(protocol.RequestCostTable)
c := &protocol.RequestCost{}
for code := range protocol.LesRequests {
serverPeer.fcCosts[code] = c
}
serverPeer.fcParams = flowcontrol.ServerParams{BufLimit: 1, MinRecharge: 1}
Expand Down
67 changes: 37 additions & 30 deletions les/checkpointoracle.go → les/checkpointoracle/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

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

import (
"encoding/binary"
Expand All @@ -28,19 +31,19 @@ import (
"github.com/ethereum/go-ethereum/params"
)

// checkpointOracle is responsible for offering the latest stable checkpoint
// generated and announced by the contract admins on-chain. The checkpoint is
// verified by clients locally during the checkpoint syncing.
type checkpointOracle struct {
// CheckpointOracle is responsible for offering the latest stable checkpoint
// generated and announced by the contract admins on-chain. The checkpoint can
// be verified by clients locally during the checkpoint syncing.
type CheckpointOracle struct {
config *params.CheckpointOracleConfig
contract *checkpointoracle.CheckpointOracle

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

// newCheckpointOracle returns a checkpoint registrar handler.
func newCheckpointOracle(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *checkpointOracle {
// NewCheckpointOracle returns a checkpoint oracle handler.
func NewCheckpointOracle(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *CheckpointOracle {
if config == nil {
log.Info("Checkpoint registrar is not enabled")
return nil
Expand All @@ -51,61 +54,65 @@ func newCheckpointOracle(config *params.CheckpointOracleConfig, getLocal func(ui
}
log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)

return &checkpointOracle{
return &CheckpointOracle{
config: config,
getLocal: getLocal,
}
}

// start binds the registrar contract and start listening to the
// newCheckpointEvent for the server side.
func (reg *checkpointOracle) start(backend bind.ContractBackend) {
contract, err := checkpointoracle.NewCheckpointOracle(reg.config.Address, backend)
// Start binds the contract backend, initializes the oracle instance
// and marks the status as available.
func (oracle *CheckpointOracle) Start(backend bind.ContractBackend) {
contract, err := checkpointoracle.NewCheckpointOracle(oracle.config.Address, backend)
if err != nil {
log.Error("Oracle contract binding failed", "err", err)
return
}
if !atomic.CompareAndSwapInt32(&reg.running, 0, 1) {
if !atomic.CompareAndSwapInt32(&oracle.running, 0, 1) {
log.Error("Already bound and listening to registrar")
return
}
reg.contract = contract
oracle.contract = contract
}

// isRunning returns an indicator whether the registrar is running.
func (reg *checkpointOracle) isRunning() bool {
return atomic.LoadInt32(&reg.running) == 1
// IsRunning returns an indicator whether the oracle is running.
func (oracle *CheckpointOracle) IsRunning() bool {
return atomic.LoadInt32(&oracle.running) == 1
}

// stableCheckpoint returns the stable checkpoint which was generated by local
// Contract returns the underlying raw checkpoint oracle contract.
func (oracle *CheckpointOracle) Contract() *checkpointoracle.CheckpointOracle {
return oracle.contract
}

// StableCheckpoint returns the stable checkpoint which was generated by local
// indexers and announced by trusted signers.
func (reg *checkpointOracle) stableCheckpoint() (*params.TrustedCheckpoint, uint64) {
func (oracle *CheckpointOracle) StableCheckpoint() (*params.TrustedCheckpoint, uint64) {
// Retrieve the latest checkpoint from the contract, abort if empty
latest, hash, height, err := reg.contract.Contract().GetLatestCheckpoint(nil)
latest, hash, height, err := oracle.contract.Contract().GetLatestCheckpoint(nil)
if err != nil || (latest == 0 && hash == [32]byte{}) {
return nil, 0
}
local := reg.getLocal(latest)
local := oracle.getLocal(latest)

// The following scenarios may occur:
//
// * local node is out of sync so that it doesn't have the
// checkpoint which registered in the contract.
// * local checkpoint doesn't match with the registered one.
//
// In both cases, server won't send the **stable** checkpoint
// to the client(no worry, client can use hardcoded one instead).
if local.HashEqual(common.Hash(hash)) {
// In both cases, no stable checkpoint will be returned.
if local.HashEqual(hash) {
return &local, height.Uint64()
}
return nil, 0
}

// verifySigners recovers the signer addresses according to the signature and
// VerifySigners recovers the signer addresses according to the signature and
// checks whether there are enough approvals to finalize the checkpoint.
func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
func (oracle *CheckpointOracle) VerifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) {
// Short circuit if the given signatures doesn't reach the threshold.
if len(signatures) < int(reg.config.Threshold) {
if len(signatures) < int(oracle.config.Threshold) {
return false, nil
}
var (
Expand All @@ -128,7 +135,7 @@ func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatur
// hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root)
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, index)
data := append([]byte{0x19, 0x00}, append(reg.config.Address.Bytes(), append(buf, hash[:]...)...)...)
data := append([]byte{0x19, 0x00}, append(oracle.config.Address.Bytes(), append(buf, hash[:]...)...)...)
signatures[i][64] -= 27 // Transform V from 27/28 to 0/1 according to the yellow paper for verification.
pubkey, err := crypto.Ecrecover(crypto.Keccak256(data), signatures[i])
if err != nil {
Expand All @@ -139,14 +146,14 @@ func (reg *checkpointOracle) verifySigners(index uint64, hash [32]byte, signatur
if _, exist := checked[signer]; exist {
continue
}
for _, s := range reg.config.Signers {
for _, s := range oracle.config.Signers {
if s == signer {
signers = append(signers, signer)
checked[signer] = struct{}{}
}
}
}
threshold := reg.config.Threshold
threshold := oracle.config.Threshold
if uint64(len(signers)) < threshold {
log.Warn("Not enough signers to approve checkpoint", "signers", len(signers), "threshold", threshold)
return false, nil
Expand Down
14 changes: 8 additions & 6 deletions les/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
Expand Down Expand Up @@ -123,7 +125,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
if oracle == nil {
oracle = params.CheckpointOracles[genesisHash]
}
leth.oracle = newCheckpointOracle(oracle, leth.localCheckpoint)
leth.oracle = checkpointoracle.NewCheckpointOracle(oracle, leth.localCheckpoint)

// Note: AddChildIndexer starts the update process for the child
leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
Expand Down Expand Up @@ -216,14 +218,14 @@ func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain }
func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool }
func (s *LightEthereum) Engine() consensus.Engine { return s.engine }
func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) }
func (s *LightEthereum) LesVersion() int { return int(protocol.ClientProtocolVersions[0]) }
func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux }

// Protocols implements node.Service, returning all the currently configured
// network protocols to start.
func (s *LightEthereum) Protocols() []p2p.Protocol {
return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
return s.makeProtocols(protocol.ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
if p := s.peers.Peer(peerIdToString(id)); p != nil {
return p.Info()
}
Expand All @@ -243,8 +245,8 @@ func (s *LightEthereum) Start(srvr *p2p.Server) error {
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId)

// clients are searching for the first advertised protocol in the list
protocolVersion := AdvertiseProtocolVersions[0]
s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
protocolVersion := protocol.AdvertiseProtocolVersions[0]
s.serverPool.start(srvr, protocol.LesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
return nil
}

Expand Down Expand Up @@ -275,5 +277,5 @@ func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) {
if s.oracle == nil {
return
}
s.oracle.start(backend)
s.oracle.Start(backend)
}
Loading