From df1ce42ba1e12bef8821fabf51124ef0ad21a1d0 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Tue, 12 Feb 2019 23:46:25 -0800 Subject: [PATCH] send staking transaction to beacon chain --- api/service/staking/service.go | 64 +++++++++++++++++++++++++++++++--- node/node.go | 6 ++-- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/api/service/staking/service.go b/api/service/staking/service.go index d09fe49b3..2c76f83a2 100644 --- a/api/service/staking/service.go +++ b/api/service/staking/service.go @@ -3,11 +3,13 @@ package staking import ( "crypto/ecdsa" "math/big" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + pb "github.com/golang/protobuf/proto" client "github.com/harmony-one/harmony/api/client/service" proto "github.com/harmony-one/harmony/api/client/service/proto" "github.com/harmony-one/harmony/api/proto/message" @@ -16,25 +18,40 @@ import ( "github.com/harmony-one/harmony/p2p" ) +type State byte + +const ( + NOT_STAKED_YET State = iota + STAKED + REJECTED + APPROVED + TRANSFORMED +) + // Service is the staking service. // Service requires private key here which is not a right design. // In stead in the right design, the end-user who runs mining needs to provide signed tx to this service. type Service struct { + host p2p.Host stopChan chan struct{} stoppedChan chan struct{} peerChan <-chan p2p.Peer + messageChan <-chan *message.Message accountKey *ecdsa.PrivateKey stakingAmount int64 + state State } // New returns staking service. -func New(accountKey *ecdsa.PrivateKey, stakingAmount int64, peerChan <-chan p2p.Peer) *Service { +func New(accountKey *ecdsa.PrivateKey, stakingAmount int64, peerChan <-chan p2p.Peer, messageChan <-chan *message.Message) *Service { return &Service{ stopChan: make(chan struct{}), stoppedChan: make(chan struct{}), peerChan: peerChan, accountKey: accountKey, stakingAmount: stakingAmount, + messageChan: messageChan, + state: NOT_STAKED_YET, } } @@ -57,7 +74,7 @@ func (s *Service) Run() { for { select { case peer := <-s.peerChan: - utils.GetLogInstance().Info("Running role conversion") + utils.GetLogInstance().Info("Running staking service") // TODO: Write some logic here. s.DoService(peer) case <-s.stopChan: @@ -71,8 +88,47 @@ func (s *Service) Run() { func (s *Service) DoService(peer p2p.Peer) { utils.GetLogInstance().Info("Staking with Peer") - // TODO(minhdoan): How to use the p2p or pubsub to send Staking Message to beacon chain. - // See below of how to create a staking message. + stakingMessage := s.createStakingMessage(peer) + s.state = STAKED + if data, err := pb.Marshal(stakingMessage); err == nil { + // Send a staking transaction to beacon chain. + if err = s.host.SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeacon}, data); err != nil { + utils.GetLogInstance().Error("Error when sending staking message") + return + } + tick := time.NewTicker(5 * time.Second) + for { + select { + // Retry sending the staking transaction if it does not get back any response. + case <-tick.C: + if err = s.host.SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeacon}, data); err != nil { + utils.GetLogInstance().Error("Error when sending staking message") + return + } + case msg := <-s.messageChan: + if isStateResultMessage(msg) { + if s.stakeApproved(msg) { + s.state = APPROVED + // TODO(minhdoan): Should send a signal to another service. + } else { + s.state = REJECTED + // TODO(minhdoan): what's next? + return + } + } + } + } + } else { + utils.GetLogInstance().Error("Error when creating staking message") + } +} + +func isStateResultMessage(msg *message.Message) bool { + return true +} + +func (s *Service) stakeApproved(msg *message.Message) bool { + return true } func (s *Service) getStakingInfo(beaconPeer p2p.Peer) *proto.StakingContractInfoResponse { diff --git a/node/node.go b/node/node.go index e4bb4208d..97ca28726 100644 --- a/node/node.go +++ b/node/node.go @@ -31,6 +31,7 @@ import ( "github.com/harmony-one/harmony/api/service/explorer" "github.com/harmony-one/harmony/api/service/networkinfo" randomness_service "github.com/harmony-one/harmony/api/service/randomness" + "github.com/harmony-one/harmony/api/service/staking" "github.com/harmony-one/harmony/api/service/syncing" "github.com/harmony-one/harmony/api/service/syncing/downloader" @@ -682,9 +683,8 @@ func (node *Node) setupForNewNode() { nodeConfig, chanPeer := node.initNodeConfiguration() // Register staking service. - // node.serviceManager.RegisterService(service_manager.Staking, staking.New(node.AccountKey, 0, stakingPeer)) - // TODO: (leo) no need to start discovery service for new node until we received the sharding info - // Register peer discovery service. + node.serviceManager.RegisterService(service_manager.Staking, staking.New(node.AccountKey, 0, stakingPeer, nil)) + // Register peer discovery service. "0" is the beacon shard ID node.serviceManager.RegisterService(service_manager.PeerDiscovery, discovery.New(node.host, nodeConfig, chanPeer)) // Register networkinfo service. "0" is the beacon shard ID node.serviceManager.RegisterService(service_manager.NetworkInfo, networkinfo.New(node.host, p2p.GroupIDBeacon, chanPeer))