From 385aff85f0c9d2e81f6307b37706f50df4e200ac Mon Sep 17 00:00:00 2001 From: Krishna Upadhyaya Date: Tue, 26 Jul 2022 02:18:37 +0530 Subject: [PATCH] Implemented heimdall gRPC client --- cmd/geth/chaincmd.go | 1 + cmd/utils/bor_flags.go | 9 ++++ cmd/utils/flags.go | 7 +-- consensus/bor/heimdallgrpc/checkpoint.go | 41 +++++++++++++++++ consensus/bor/heimdallgrpc/client.go | 37 +++++++++++++++ consensus/bor/heimdallgrpc/span.go | 57 ++++++++++++++++++++++++ consensus/bor/heimdallgrpc/state_sync.go | 49 ++++++++++++++++++++ consensus/bor/heimdallgrpc/type_utils.go | 42 +++++++++++++++++ eth/ethconfig/config.go | 3 ++ go.mod | 3 +- go.sum | 6 ++- internal/cli/server/config.go | 9 +++- internal/cli/server/flags.go | 6 +++ 13 files changed, 262 insertions(+), 8 deletions(-) create mode 100644 consensus/bor/heimdallgrpc/checkpoint.go create mode 100644 consensus/bor/heimdallgrpc/client.go create mode 100644 consensus/bor/heimdallgrpc/span.go create mode 100644 consensus/bor/heimdallgrpc/state_sync.go create mode 100644 consensus/bor/heimdallgrpc/type_utils.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index a178f6c751..fc2309d2db 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -108,6 +108,7 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to // bor related flags utils.HeimdallURLFlag, utils.WithoutHeimdallFlag, + utils.HeimdallgRPCAddressFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` diff --git a/cmd/utils/bor_flags.go b/cmd/utils/bor_flags.go index 34355532e1..6369b251c6 100644 --- a/cmd/utils/bor_flags.go +++ b/cmd/utils/bor_flags.go @@ -31,10 +31,18 @@ var ( Usage: "Run without Heimdall service (for testing purpose)", } + // HeimdallgRPCAddressFlag flag for heimdall gRPC address + HeimdallgRPCAddressFlag = cli.StringFlag{ + Name: "bor.heimdallgRPC", + Usage: "Address of Heimdall gRPC service", + Value: ":3132", + } + // BorFlags all bor related flags BorFlags = []cli.Flag{ HeimdallURLFlag, WithoutHeimdallFlag, + HeimdallgRPCAddressFlag, } ) @@ -57,6 +65,7 @@ func getGenesis(genesisPath string) (*core.Genesis, error) { func SetBorConfig(ctx *cli.Context, cfg *eth.Config) { cfg.HeimdallURL = ctx.GlobalString(HeimdallURLFlag.Name) cfg.WithoutHeimdall = ctx.GlobalBool(WithoutHeimdallFlag.Name) + cfg.HeimdallgRPCAddress = ctx.GlobalString(HeimdallgRPCAddressFlag.Name) } // CreateBorEthereum Creates bor ethereum object from eth.Config diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 1a593888d6..68069eeba7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2024,9 +2024,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai engine = clique.New(config.Clique, chainDb) } else if config.Bor != nil { ethereum = CreateBorEthereum(ð.Config{ - Genesis: genesis, - HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name), - WithoutHeimdall: ctx.GlobalBool(WithoutHeimdallFlag.Name), + Genesis: genesis, + HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name), + WithoutHeimdall: ctx.GlobalBool(WithoutHeimdallFlag.Name), + HeimdallgRPCAddress: ctx.GlobalString(HeimdallgRPCAddressFlag.Name), }) engine = ethereum.Engine() } else { diff --git a/consensus/bor/heimdallgrpc/checkpoint.go b/consensus/bor/heimdallgrpc/checkpoint.go new file mode 100644 index 0000000000..ef25897237 --- /dev/null +++ b/consensus/bor/heimdallgrpc/checkpoint.go @@ -0,0 +1,41 @@ +package heimdallgrpc + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + + proto "github.com/maticnetwork/polyproto/heimdall" +) + +func (h *HeimdallGRPCClient) FetchCheckpointCount(ctx context.Context) (int64, error) { + res, err := h.client.FetchCheckpointCount(context.Background(), nil) + if err != nil { + return 0, err + } + + return res.Result.Result, nil +} + +func (h *HeimdallGRPCClient) FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) { + req := &proto.FetchCheckpointRequest{ + ID: number, + } + + res, err := h.client.FetchCheckpoint(context.Background(), req) + if err != nil { + return nil, err + } + + checkpoint := &checkpoint.Checkpoint{ + StartBlock: new(big.Int).SetUint64(res.Result.StartBlock), + EndBlock: new(big.Int).SetUint64(res.Result.EndBlock), + RootHash: ConvertH256ToHash(res.Result.RootHash), + Proposer: ConvertH160toAddress(res.Result.Proposer), + BorChainID: res.Result.BorChainID, + Timestamp: uint64(res.Result.Timestamp.GetSeconds()), + } + + return checkpoint, nil +} diff --git a/consensus/bor/heimdallgrpc/client.go b/consensus/bor/heimdallgrpc/client.go new file mode 100644 index 0000000000..a52fc20dca --- /dev/null +++ b/consensus/bor/heimdallgrpc/client.go @@ -0,0 +1,37 @@ +package heimdallgrpc + +import ( + "log" + + proto "github.com/maticnetwork/polyproto/heimdall" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + stateFetchLimit = 50 +) + +type HeimdallGRPCClient struct { + conn *grpc.ClientConn + client proto.HeimdallClient + closeCh chan struct{} +} + +func NewHeimdallGRPCClient(address string) *HeimdallGRPCClient { + conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("Failed to connect to Heimdall gRPC server: %v", err) + } + + return &HeimdallGRPCClient{ + conn: conn, + client: proto.NewHeimdallClient(conn), + closeCh: make(chan struct{}), + } +} + +func (h *HeimdallGRPCClient) Close() { + close(h.closeCh) + h.conn.Close() +} diff --git a/consensus/bor/heimdallgrpc/span.go b/consensus/bor/heimdallgrpc/span.go new file mode 100644 index 0000000000..cfd9d7ffd9 --- /dev/null +++ b/consensus/bor/heimdallgrpc/span.go @@ -0,0 +1,57 @@ +package heimdallgrpc + +import ( + "context" + + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/valset" + + proto "github.com/maticnetwork/polyproto/heimdall" +) + +func (h *HeimdallGRPCClient) Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error) { + req := &proto.SpanRequest{ + ID: spanID, + } + + res, err := h.client.Span(context.Background(), req) + if err != nil { + return nil, err + } + + return parseSpan(res.Result), nil +} + +func parseSpan(protoSpan *proto.Span) *span.HeimdallSpan { + resp := &span.HeimdallSpan{ + Span: span.Span{ + ID: protoSpan.ID, + StartBlock: protoSpan.StartBlock, + EndBlock: protoSpan.EndBlock, + }, + ValidatorSet: valset.ValidatorSet{}, + SelectedProducers: []valset.Validator{}, + ChainID: protoSpan.ChainID, + } + + for _, validator := range protoSpan.ValidatorSet.Validators { + resp.ValidatorSet.Validators = append(resp.ValidatorSet.Validators, parseValidator(validator)) + } + + resp.ValidatorSet.Proposer = parseValidator(protoSpan.ValidatorSet.Proposer) + + for _, validator := range protoSpan.SelectedProducers { + resp.SelectedProducers = append(resp.SelectedProducers, *parseValidator(validator)) + } + + return resp +} + +func parseValidator(validator *proto.Validator) *valset.Validator { + return &valset.Validator{ + ID: validator.ID, + Address: ConvertH160toAddress(validator.Address), + VotingPower: validator.VotingPower, + ProposerPriority: validator.ProposerPriority, + } +} diff --git a/consensus/bor/heimdallgrpc/state_sync.go b/consensus/bor/heimdallgrpc/state_sync.go new file mode 100644 index 0000000000..aaa4736548 --- /dev/null +++ b/consensus/bor/heimdallgrpc/state_sync.go @@ -0,0 +1,49 @@ +package heimdallgrpc + +import ( + "context" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" + + proto "github.com/maticnetwork/polyproto/heimdall" +) + +func (h *HeimdallGRPCClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) { + eventRecords := make([]*clerk.EventRecordWithTime, 0) + + req := &proto.StateSyncEventsRequest{ + FromID: fromID, + ToTime: uint64(to), + Limit: uint64(stateFetchLimit), + } + + res, err := h.client.StateSyncEvents(context.Background(), req) + if err != nil { + return nil, err + } + + for { + events, err := res.Recv() + if err != nil { + break + } + + for _, event := range events.Result { + eventRecord := &clerk.EventRecordWithTime{ + EventRecord: clerk.EventRecord{ + ID: event.ID, + Contract: common.HexToAddress(event.Contract), + Data: common.Hex2Bytes(event.Data[2:]), + TxHash: common.HexToHash(event.TxHash), + LogIndex: event.LogIndex, + ChainID: event.ChainID, + }, + Time: event.Time.AsTime(), + } + eventRecords = append(eventRecords, eventRecord) + } + } + + return eventRecords, nil +} diff --git a/consensus/bor/heimdallgrpc/type_utils.go b/consensus/bor/heimdallgrpc/type_utils.go new file mode 100644 index 0000000000..daa58da115 --- /dev/null +++ b/consensus/bor/heimdallgrpc/type_utils.go @@ -0,0 +1,42 @@ +package heimdallgrpc + +import ( + "encoding/binary" + + proto "github.com/maticnetwork/polyproto/heimdall" +) + +func ConvertH160toAddress(h160 *proto.H160) [20]byte { + var addr [20]byte + + binary.BigEndian.PutUint64(addr[0:], h160.Hi.Hi) + binary.BigEndian.PutUint64(addr[8:], h160.Hi.Lo) + binary.BigEndian.PutUint32(addr[16:], h160.Lo) + + return addr +} + +func ConvertAddressToH160(addr [20]byte) *proto.H160 { + return &proto.H160{ + Lo: binary.BigEndian.Uint32(addr[16:]), + Hi: &proto.H128{Lo: binary.BigEndian.Uint64(addr[8:]), Hi: binary.BigEndian.Uint64(addr[0:])}, + } +} + +func ConvertH256ToHash(h256 *proto.H256) [32]byte { + var hash [32]byte + + binary.BigEndian.PutUint64(hash[0:], h256.Hi.Hi) + binary.BigEndian.PutUint64(hash[8:], h256.Hi.Lo) + binary.BigEndian.PutUint64(hash[16:], h256.Lo.Hi) + binary.BigEndian.PutUint64(hash[24:], h256.Lo.Lo) + + return hash +} + +func ConvertHashToH256(hash [32]byte) *proto.H256 { + return &proto.H256{ + Lo: &proto.H128{Lo: binary.BigEndian.Uint64(hash[24:]), Hi: binary.BigEndian.Uint64(hash[16:])}, + Hi: &proto.H128{Lo: binary.BigEndian.Uint64(hash[8:]), Hi: binary.BigEndian.Uint64(hash[0:])}, + } +} diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index d51e293413..10616b60c5 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -216,6 +216,9 @@ type Config struct { // No heimdall service WithoutHeimdall bool + // Address to connect to Heimdall gRPC server + HeimdallgRPCAddress string + // Bor logs flag BorLogs bool diff --git a/go.mod b/go.mod index 8c5c18f8c7..85d4ba5ece 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 + github.com/maticnetwork/polyproto v0.0.1 github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 @@ -71,7 +72,7 @@ require ( golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.10 - google.golang.org/grpc v1.47.0 + google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 diff --git a/go.sum b/go.sum index e20575ddaa..90c3d5d229 100644 --- a/go.sum +++ b/go.sum @@ -337,6 +337,8 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/maticnetwork/polyproto v0.0.1 h1:qdxoyGd9EkYs910n4crEQqZETpvpRSrprlDYtdbZrqg= +github.com/maticnetwork/polyproto v0.0.1/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -738,8 +740,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index fdf253a37e..522d4004ae 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -153,6 +153,9 @@ type HeimdallConfig struct { // Without is used to disable remote heimdall during testing Without bool `hcl:"without,optional"` + + // GRPCAddress is the address of the heimdall grpc server + GRPCAddress string `hcl:"grpc-address,optional"` } type TxPoolConfig struct { @@ -409,8 +412,9 @@ func DefaultConfig() *Config { }, }, Heimdall: &HeimdallConfig{ - URL: "http://localhost:1317", - Without: false, + URL: "http://localhost:1317", + Without: false, + GRPCAddress: ":3132", }, SyncMode: "full", GcMode: "full", @@ -652,6 +656,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* } n.HeimdallURL = c.Heimdall.URL n.WithoutHeimdall = c.Heimdall.Without + n.HeimdallgRPCAddress = c.Heimdall.GRPCAddress // gas price oracle { diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index e85428b9ee..fd48d226f9 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -80,6 +80,12 @@ func (c *Command) Flags() *flagset.Flagset { Value: &c.cliConfig.Heimdall.Without, Default: c.cliConfig.Heimdall.Without, }) + f.StringFlag(&flagset.StringFlag{ + Name: "bor.heimdallgRPC", + Usage: "Address of Heimdall gRPC service", + Value: &c.cliConfig.Heimdall.GRPCAddress, + Default: c.cliConfig.Heimdall.GRPCAddress, + }) // txpool options f.SliceStringFlag(&flagset.SliceStringFlag{