Merge pull request #1706 from rlan35/mainnet_release_1005_merge_s3

Mainnet release 1005 merge s3
pull/1726/head
Rongjian Lan 5 years ago committed by GitHub
commit cbb2d4997f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      accounts/keystore/keystore.go
  2. 39
      api/service/config.go
  3. 26
      api/service/discovery/service.go
  4. 17
      api/service/explorer/service.go
  5. 8
      api/service/explorer/storage.go
  6. 21
      api/service/explorer/structs.go
  7. 5
      api/service/manager_test.go
  8. 15
      api/service/networkinfo/service.go
  9. 3
      api/service/networkinfo/service_test.go
  10. 10
      cmd/client/txgen/main.go
  11. 4
      cmd/client/wallet/main.go
  12. 4
      cmd/client/wallet_stress_test/main.go
  13. 34
      cmd/harmony/main.go
  14. 24
      cmd/staking/main.go
  15. 173
      cmd/staking/root.go
  16. 7
      consensus/consensus_msg_sender.go
  17. 16
      consensus/consensus_v2.go
  18. 11
      consensus/view_change.go
  19. 7
      core/error.go
  20. 4
      drand/drand_leader.go
  21. 4
      drand/drand_validator.go
  22. 1
      go.mod
  23. 9
      hmy/api_backend.go
  24. 2
      hmy/backend.go
  25. 36
      internal/configs/node/config.go
  26. 8
      internal/configs/node/config_test.go
  27. 55
      internal/configs/node/group.go
  28. 2
      internal/configs/node/group_test.go
  29. 3
      internal/hmyapi/backend.go
  30. 2
      internal/hmyapi/blockchain.go
  31. 72
      internal/hmyapi/transactionpool.go
  32. 34
      internal/hmyapi/types.go
  33. 38
      internal/hmyapi/util.go
  34. 42
      node/node.go
  35. 6
      node/node_cross_shard.go
  36. 15
      node/node_handler.go
  37. 1
      node/node_newblock.go
  38. 4
      node/node_resharding.go
  39. 7
      node/service_setup.go
  40. 28
      node/worker/worker.go
  41. 10
      node/worker/worker_test.go
  42. 5
      p2p/host.go
  43. 5
      p2p/host/hostv2/hostv2.go
  44. 6
      p2p/host/hostv2/hostv2_test.go
  45. 5
      p2p/host/mock/host_mock.go
  46. 11
      p2p/p2p.go
  47. 7
      scripts/go_executable_build.sh
  48. 9
      staking/types/commission.go
  49. 1
      staking/types/decimal_test.go
  50. 247
      staking/types/delegation.go
  51. 232
      staking/types/messages.go
  52. 413
      staking/types/messages_test.go
  53. 199
      staking/types/sign.go
  54. 39
      staking/types/staking_transaction.go
  55. 110
      staking/types/transaction.go
  56. 17
      staking/types/validator.go
  57. 19
      test/chain/main.go

@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/core/types"
staking "github.com/harmony-one/harmony/staking/types"
)
// ErrLocked ...
@ -299,6 +300,20 @@ func (ks *KeyStore) SignHashWithPassphrase(a accounts.Account, passphrase string
return crypto.Sign(hash, key.PrivateKey)
}
// SignStakingTx signs a staking transaction, only EIP155 based signer
func (ks *KeyStore) SignStakingTx(
a accounts.Account,
tx *staking.StakingTransaction,
chainID *big.Int) (*staking.StakingTransaction, error) {
ks.mu.RLock()
defer ks.mu.RUnlock()
unlockedKey, found := ks.unlocked[a.Address]
if !found {
return nil, ErrLocked
}
return staking.Sign(tx, staking.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
}
// SignTxWithPassphrase signs the transaction if the private key matching the
// given address can be decrypted with the given passphrase.
func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {

@ -2,7 +2,6 @@ package service
import (
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/p2p"
)
// NodeConfig defines a structure of node configuration
@ -11,37 +10,37 @@ import (
// cyclic imports
type NodeConfig struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
Beacon p2p.GroupID // the beacon group ID
ShardGroupID p2p.GroupID // the group ID of the shard
Client p2p.GroupID // the client group ID of the shard
IsClient bool // whether this node is a client node, such as wallet/txgen
IsBeacon bool // whether this node is a beacon node or not
ShardID uint32 // shardID of this node
Actions map[p2p.GroupID]p2p.ActionType // actions on the groups
PushgatewayIP string // prometheus pushgateway ip
PushgatewayPort string // prometheus pushgateway port
MetricsFlag bool // flag to collect metrics or not
Beacon nodeconfig.GroupID // the beacon group ID
ShardGroupID nodeconfig.GroupID // the group ID of the shard
Client nodeconfig.GroupID // the client group ID of the shard
IsClient bool // whether this node is a client node, such as wallet/txgen
IsBeacon bool // whether this node is a beacon node or not
ShardID uint32 // shardID of this node
Actions map[nodeconfig.GroupID]nodeconfig.ActionType // actions on the groups
PushgatewayIP string // prometheus pushgateway ip
PushgatewayPort string // prometheus pushgateway port
MetricsFlag bool // flag to collect metrics or not
}
// GroupIDShards is a map of ShardGroupID ID
// key is the shard ID
// value is the corresponding group ID
var (
GroupIDShards map[p2p.ShardID]p2p.GroupID
GroupIDShardClients map[p2p.ShardID]p2p.GroupID
GroupIDShards map[nodeconfig.ShardID]nodeconfig.GroupID
GroupIDShardClients map[nodeconfig.ShardID]nodeconfig.GroupID
)
func init() {
GroupIDShards = make(map[p2p.ShardID]p2p.GroupID)
GroupIDShardClients = make(map[p2p.ShardID]p2p.GroupID)
GroupIDShards = make(map[nodeconfig.ShardID]nodeconfig.GroupID)
GroupIDShardClients = make(map[nodeconfig.ShardID]nodeconfig.GroupID)
// init beacon chain group IDs
GroupIDShards[0] = p2p.GroupIDBeacon
GroupIDShardClients[0] = p2p.GroupIDBeaconClient
GroupIDShards[0] = nodeconfig.NewGroupIDByShardID(0)
GroupIDShardClients[0] = nodeconfig.NewClientGroupIDByShardID(0)
for i := 1; i < nodeconfig.MaxShards; i++ {
sid := p2p.ShardID(i)
GroupIDShards[sid] = p2p.NewGroupIDByShardID(sid)
GroupIDShardClients[sid] = p2p.NewClientGroupIDByShardID(sid)
sid := nodeconfig.ShardID(i)
GroupIDShards[sid] = nodeconfig.NewGroupIDByShardID(sid)
GroupIDShardClients[sid] = nodeconfig.NewClientGroupIDByShardID(sid)
}
}

@ -18,9 +18,9 @@ type Service struct {
host p2p.Host
peerChan chan p2p.Peer
stopChan chan struct{}
actionChan chan p2p.GroupAction
actionChan chan nodeconfig.GroupAction
config service.NodeConfig
actions map[p2p.GroupID]p2p.ActionType
actions map[nodeconfig.GroupID]nodeconfig.ActionType
messageChan chan *msg_pb.Message
addBeaconPeerFunc func(*p2p.Peer) bool
}
@ -34,9 +34,9 @@ func New(h p2p.Host, config service.NodeConfig, peerChan chan p2p.Peer, addPeer
host: h,
peerChan: peerChan,
stopChan: make(chan struct{}),
actionChan: make(chan p2p.GroupAction),
actionChan: make(chan nodeconfig.GroupAction),
config: config,
actions: make(map[p2p.GroupID]p2p.ActionType),
actions: make(map[nodeconfig.GroupID]nodeconfig.ActionType),
addBeaconPeerFunc: addPeer,
}
}
@ -58,7 +58,7 @@ func (s *Service) StopService() {
// NotifyService receives notification from service manager
func (s *Service) NotifyService(params map[string]interface{}) {
data := params["peer"]
action, ok := data.(p2p.GroupAction)
action, ok := data.(nodeconfig.GroupAction)
if !ok {
utils.Logger().Error().Msg("Wrong data type passed to NotifyService")
return
@ -117,18 +117,14 @@ func (s *Service) contactP2pPeers() {
}
// sentPingMessage sends a ping message to a pubsub topic
func (s *Service) sentPingMessage(g p2p.GroupID, msgBuf []byte) {
func (s *Service) sentPingMessage(g nodeconfig.GroupID, msgBuf []byte) {
var err error
if g == p2p.GroupIDBeacon || g == p2p.GroupIDBeaconClient {
err = s.host.SendMessageToGroups([]p2p.GroupID{s.config.Beacon}, msgBuf)
} else {
// The following logical will be used for 2nd stage peer discovery process
// do nothing when the groupID is unknown
if s.config.ShardGroupID == p2p.GroupIDUnknown {
return
}
err = s.host.SendMessageToGroups([]p2p.GroupID{s.config.ShardGroupID}, msgBuf)
// The following logical will be used for 2nd stage peer discovery process
// do nothing when the groupID is unknown
if s.config.ShardGroupID == nodeconfig.GroupIDUnknown {
return
}
err = s.host.SendMessageToGroups([]nodeconfig.GroupID{s.config.ShardGroupID}, msgBuf)
if err != nil {
utils.Logger().Error().Err(err).Str("group", string(g)).Msg("Failed to send ping message")
}

@ -339,7 +339,9 @@ func (s *Service) GetExplorerBlocks(w http.ResponseWriter, r *http.Request) {
}
data.Blocks = append(data.Blocks, block)
}
if offset*page+offset > len(data.Blocks) {
if offset*page >= len(data.Blocks) {
data.Blocks = []*Block{}
} else if offset*page+offset > len(data.Blocks) {
data.Blocks = data.Blocks[offset*page:]
} else {
data.Blocks = data.Blocks[offset*page : offset*page+offset]
@ -458,7 +460,9 @@ func (s *ServiceAPI) GetExplorerBlocks(ctx context.Context, from, to, page, offs
}
blocks = append(blocks, block)
}
if offset*page+offset > len(blocks) {
if offset*page >= len(blocks) {
blocks = []*Block{}
} else if offset*page+offset > len(blocks) {
blocks = blocks[offset*page:]
} else {
blocks = blocks[offset*page : offset*page+offset]
@ -765,7 +769,9 @@ func (s *Service) GetExplorerAddress(w http.ResponseWriter, r *http.Request) {
}
data.Address.TXs = sentTXs
}
if offset*page+offset > len(data.Address.TXs) {
if offset*page >= len(data.Address.TXs) {
data.Address.TXs = []*Transaction{}
} else if offset*page+offset > len(data.Address.TXs) {
data.Address.TXs = data.Address.TXs[offset*page:]
} else {
data.Address.TXs = data.Address.TXs[offset*page : offset*page+offset]
@ -852,7 +858,10 @@ func (s *ServiceAPI) GetExplorerAddress(ctx context.Context, id, txView string,
}
address.TXs = sentTXs
}
if offset*page+offset > len(address.TXs) {
if offset*page >= len(address.TXs) {
address.TXs = []*Transaction{}
} else if offset*page+offset > len(address.TXs) {
address.TXs = address.TXs[offset*page:]
} else {
address.TXs = address.TXs[offset*page : offset*page+offset]

@ -112,10 +112,6 @@ func (storage *Storage) Dump(block *types.Block, height uint64) {
// Store txs
for _, tx := range block.Transactions() {
if tx.To() == nil {
continue
}
explorerTransaction := GetTransaction(tx, block)
storage.UpdateTXStorage(batch, explorerTransaction, tx)
storage.UpdateAddress(batch, explorerTransaction, tx)
@ -158,7 +154,9 @@ func (storage *Storage) UpdateTXStorage(batch ethdb.Batch, explorerTransaction *
// TODO: deprecate this logic
func (storage *Storage) UpdateAddress(batch ethdb.Batch, explorerTransaction *Transaction, tx *types.Transaction) {
explorerTransaction.Type = Received
storage.UpdateAddressStorage(batch, explorerTransaction.To, explorerTransaction, tx)
if explorerTransaction.To != "" {
storage.UpdateAddressStorage(batch, explorerTransaction.To, explorerTransaction, tx)
}
explorerTransaction.Type = Sent
storage.UpdateAddressStorage(batch, explorerTransaction.From, explorerTransaction, tx)
}

@ -5,10 +5,8 @@ import (
"math/big"
"strconv"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
)
@ -114,20 +112,27 @@ func NewBlock(block *types.Block, height int) *Block {
// GetTransaction ...
func GetTransaction(tx *types.Transaction, addressBlock *types.Block) *Transaction {
if tx.To() == nil {
return nil
}
msg, err := tx.AsMessage(types.NewEIP155Signer(tx.ChainID()))
if err != nil {
utils.Logger().Error().Err(err).Msg("Error when parsing tx into message")
}
gasFee := big.NewInt(0)
gasFee = gasFee.Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
to := ""
if msg.To() != nil {
if to, err = common.AddressToBech32(*msg.To()); err != nil {
return nil
}
}
from := ""
if from, err = common.AddressToBech32(msg.From()); err != nil {
return nil
}
return &Transaction{
ID: tx.Hash().Hex(),
Timestamp: strconv.Itoa(int(addressBlock.Time().Int64() * 1000)),
From: common2.MustAddressToBech32(common.HexToAddress(msg.From().Hex())),
To: common2.MustAddressToBech32(common.HexToAddress(msg.To().Hex())),
From: from,
To: to,
Value: msg.Value(),
Bytes: strconv.Itoa(int(tx.Size())),
Data: hex.EncodeToString(tx.Data()),

@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/rpc"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/p2p"
)
type SupportSyncingTest struct {
@ -102,8 +101,8 @@ func TestStopServices(t *testing.T) {
}
func TestInit(t *testing.T) {
if GroupIDShards[p2p.ShardID(0)] != p2p.GroupIDBeacon {
t.Errorf("GroupIDShards[0]: %v != GroupIDBeacon: %v", GroupIDShards[p2p.ShardID(0)], p2p.GroupIDBeacon)
if GroupIDShards[nodeconfig.ShardID(0)] != nodeconfig.NewGroupIDByShardID(0) {
t.Errorf("GroupIDShards[0]: %v != GroupIDBeacon: %v", GroupIDShards[nodeconfig.ShardID(0)], nodeconfig.NewGroupIDByShardID(0))
}
if len(GroupIDShards) != nodeconfig.MaxShards {
t.Errorf("len(GroupIDShards): %v != TotalShards: %v", len(GroupIDShards), nodeconfig.MaxShards)

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
badger "github.com/ipfs/go-ds-badger"
@ -25,7 +26,7 @@ import (
// Service is the network info service.
type Service struct {
Host p2p.Host
Rendezvous p2p.GroupID
Rendezvous nodeconfig.GroupID
bootnodes utils.AddrList
dht *libp2pdht.IpfsDHT
cancel context.CancelFunc
@ -61,7 +62,7 @@ const (
// New returns role conversion service. If dataStorePath is not empty, it
// points to a persistent database directory to use.
func New(
h p2p.Host, rendezvous p2p.GroupID, peerChan chan p2p.Peer,
h p2p.Host, rendezvous nodeconfig.GroupID, peerChan chan p2p.Peer,
bootnodes utils.AddrList, dataStorePath string,
) (*Service, error) {
var cancel context.CancelFunc
@ -100,7 +101,7 @@ func New(
// MustNew is a panic-on-error version of New.
func MustNew(
h p2p.Host, rendezvous p2p.GroupID, peerChan chan p2p.Peer,
h p2p.Host, rendezvous nodeconfig.GroupID, peerChan chan p2p.Peer,
bootnodes utils.AddrList, dataStorePath string,
) *Service {
service, err := New(h, rendezvous, peerChan, bootnodes, dataStorePath)
@ -167,7 +168,10 @@ func (s *Service) Init() error {
utils.Logger().Info().Str("Rendezvous", string(s.Rendezvous)).Msg("Announcing ourselves...")
s.discovery = libp2pdis.NewRoutingDiscovery(s.dht)
libp2pdis.Advertise(ctx, s.discovery, string(s.Rendezvous))
libp2pdis.Advertise(ctx, s.discovery, string(p2p.GroupIDBeaconClient))
// Everyone is beacon client, which means everyone is connected via beacon client topic
// 0 is beacon chain FIXME: use a constant
libp2pdis.Advertise(ctx, s.discovery, string(nodeconfig.NewClientGroupIDByShardID(0)))
utils.Logger().Info().Msg("Successfully announced!")
return nil
@ -193,7 +197,8 @@ func (s *Service) DoService() {
return
case <-tick.C:
libp2pdis.Advertise(ctx, s.discovery, string(s.Rendezvous))
libp2pdis.Advertise(ctx, s.discovery, string(p2p.GroupIDBeaconClient))
// 0 is beacon chain FIXME: use a constant
libp2pdis.Advertise(ctx, s.discovery, string(nodeconfig.NewClientGroupIDByShardID(0)))
utils.Logger().Info().Str("Rendezvous", string(s.Rendezvous)).Msg("Successfully announced!")
default:
var err error

@ -6,6 +6,7 @@ import (
"github.com/harmony-one/harmony/crypto/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
@ -28,7 +29,7 @@ func TestService(t *testing.T) {
t.Fatal("unable to new host in harmony")
}
s, err := New(host, p2p.GroupIDBeaconClient, nil, nil, "")
s, err := New(host, nodeconfig.GroupIDBeaconClient, nil, nil, "")
if err != nil {
t.Fatalf("New() failed: %s", err)
}

@ -119,9 +119,9 @@ func setUpTXGen() *node.Node {
}
txGen.NodeConfig.SetRole(nodeconfig.ClientNode)
if shardID == 0 {
txGen.NodeConfig.SetShardGroupID(p2p.GroupIDBeacon)
txGen.NodeConfig.SetShardGroupID(nodeconfig.GroupIDBeacon)
} else {
txGen.NodeConfig.SetShardGroupID(p2p.NewGroupIDByShardID(p2p.ShardID(shardID)))
txGen.NodeConfig.SetShardGroupID(nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(shardID)))
}
txGen.NodeConfig.SetIsClient(true)
@ -289,10 +289,10 @@ func SendTxsToShard(clientNode *node.Node, txs types.Transactions, shardID uint3
msg := proto_node.ConstructTransactionListMessageAccount(txs)
var err error
if shardID == 0 {
err = clientNode.GetHost().SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg))
err = clientNode.GetHost().SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg))
} else {
clientGroup := p2p.NewClientGroupIDByShardID(p2p.ShardID(shardID))
err = clientNode.GetHost().SendMessageToGroups([]p2p.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
clientGroup := nodeconfig.NewClientGroupIDByShardID(nodeconfig.ShardID(shardID))
err = clientNode.GetHost().SendMessageToGroups([]nodeconfig.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
}
if err != nil {
utils.Logger().Debug().

@ -935,9 +935,9 @@ func clearKeystore() {
// submitTransaction submits the transaction to the Harmony network
func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error {
msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx})
clientGroup := p2p.NewClientGroupIDByShardID(p2p.ShardID(shardID))
clientGroup := nodeconfig.NewClientGroupIDByShardID(nodeconfig.ShardID(shardID))
err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
err := walletNode.GetHost().SendMessageToGroups([]nodeconfig.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
if err != nil {
fmt.Printf("Error in SubmitTransaction: %v\n", err)
return err

@ -457,9 +457,9 @@ func clearKeystore() {
// submitTransaction submits the transaction to the Harmony network
func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error {
msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx})
clientGroup := p2p.NewClientGroupIDByShardID(p2p.ShardID(shardID))
clientGroup := nodeconfig.NewClientGroupIDByShardID(nodeconfig.ShardID(shardID))
err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
err := walletNode.GetHost().SendMessageToGroups([]nodeconfig.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg))
if err != nil {
fmt.Printf("Error in SubmitTransaction: %v\n", err)
return err

@ -35,6 +35,7 @@ import (
"github.com/harmony-one/harmony/p2p/p2pimpl"
)
// Version string variables
var (
version string
builtBy string
@ -42,6 +43,11 @@ var (
commit string
)
// Host
var (
myHost p2p.Host
)
// InitLDBDatabase initializes a LDBDatabase. isGenesis=true will return the beacon chain database for normal shard nodes
func InitLDBDatabase(ip string, port string, freshDB bool, isBeacon bool) (*ethdb.LDBDatabase, error) {
var dbFileName string
@ -64,6 +70,7 @@ func printVersion() {
os.Exit(0)
}
// Flags
var (
ip = flag.String("ip", "127.0.0.1", "ip of the node")
port = flag.String("port", "9000", "port of the node.")
@ -262,11 +269,12 @@ func createGlobalConfig() *nodeconfig.ConfigType {
if err != nil {
panic(err)
}
nodeConfig.SelfPeer = p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: nodeConfig.ConsensusPubKey}
nodeConfig.Host, err = p2pimpl.NewHost(&nodeConfig.SelfPeer, nodeConfig.P2pPriKey)
selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: nodeConfig.ConsensusPubKey}
myHost, err = p2pimpl.NewHost(&selfPeer, nodeConfig.P2pPriKey)
if *logConn && nodeConfig.GetNetworkType() != nodeconfig.Mainnet {
nodeConfig.Host.GetP2PHost().Network().Notify(utils.NewConnLogger(utils.GetLogInstance()))
myHost.GetP2PHost().Network().Notify(utils.NewConnLogger(utils.GetLogInstance()))
}
if err != nil {
panic("unable to new host in harmony")
@ -281,7 +289,7 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
// Consensus object.
// TODO: consensus object shouldn't start here
// TODO(minhdoan): During refactoring, found out that the peers list is actually empty. Need to clean up the logic of consensus later.
currentConsensus, err := consensus.New(nodeConfig.Host, nodeConfig.ShardID, nodeConfig.Leader, nodeConfig.ConsensusPriKey)
currentConsensus, err := consensus.New(myHost, nodeConfig.ShardID, p2p.Peer{}, nodeConfig.ConsensusPriKey)
currentConsensus.SelfAddress = common.ParseAddr(initialAccount.Address)
if err != nil {
@ -302,7 +310,7 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
// Current node.
chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir}
currentNode := node.New(nodeConfig.Host, currentConsensus, chainDBFactory, *isArchival)
currentNode := node.New(myHost, currentConsensus, chainDBFactory, *isArchival)
switch {
case *networkType == nodeconfig.Localnet:
@ -338,21 +346,21 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
currentNode.NodeConfig.SetPushgatewayPort(nodeConfig.PushgatewayPort)
currentNode.NodeConfig.SetMetricsFlag(nodeConfig.MetricsFlag)
currentNode.NodeConfig.SetBeaconGroupID(p2p.NewGroupIDByShardID(0))
currentNode.NodeConfig.SetBeaconGroupID(nodeconfig.NewGroupIDByShardID(0))
switch *nodeType {
case "explorer":
currentNode.NodeConfig.SetRole(nodeconfig.ExplorerNode)
currentNode.NodeConfig.SetShardGroupID(p2p.NewGroupIDByShardID(p2p.ShardID(*shardID)))
currentNode.NodeConfig.SetClientGroupID(p2p.NewClientGroupIDByShardID(p2p.ShardID(*shardID)))
currentNode.NodeConfig.SetShardGroupID(nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(*shardID)))
currentNode.NodeConfig.SetClientGroupID(nodeconfig.NewClientGroupIDByShardID(nodeconfig.ShardID(*shardID)))
case "validator":
currentNode.NodeConfig.SetRole(nodeconfig.Validator)
if nodeConfig.ShardID == 0 {
currentNode.NodeConfig.SetShardGroupID(p2p.GroupIDBeacon)
currentNode.NodeConfig.SetClientGroupID(p2p.GroupIDBeaconClient)
currentNode.NodeConfig.SetShardGroupID(nodeconfig.NewGroupIDByShardID(0))
currentNode.NodeConfig.SetClientGroupID(nodeconfig.NewClientGroupIDByShardID(0))
} else {
currentNode.NodeConfig.SetShardGroupID(p2p.NewGroupIDByShardID(p2p.ShardID(nodeConfig.ShardID)))
currentNode.NodeConfig.SetClientGroupID(p2p.NewClientGroupIDByShardID(p2p.ShardID(nodeConfig.ShardID)))
currentNode.NodeConfig.SetShardGroupID(nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(nodeConfig.ShardID)))
currentNode.NodeConfig.SetClientGroupID(nodeconfig.NewClientGroupIDByShardID(nodeconfig.ShardID(nodeConfig.ShardID)))
}
}
currentNode.NodeConfig.ConsensusPubKey = nodeConfig.ConsensusPubKey
@ -479,7 +487,7 @@ func main() {
Str("BeaconGroupID", nodeConfig.GetBeaconGroupID().String()).
Str("ClientGroupID", nodeConfig.GetClientGroupID().String()).
Str("Role", currentNode.NodeConfig.Role().String()).
Str("multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, nodeConfig.Host.GetID().Pretty())).
Str("multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, myHost.GetID().Pretty())).
Msg(startMsg)
if *enableMemProfiling {

@ -0,0 +1,24 @@
package main
import (
"fmt"
"os"
)
var (
version string
commit string
builtAt string
builtBy string
)
func main() {
if os.Args[1] == "-version" {
fmt.Fprintf(os.Stderr, versionS()+"\n")
os.Exit(0)
}
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}

@ -0,0 +1,173 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"os"
"path"
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/accounts/keystore"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/spf13/cobra"
)
const (
keystoreDir = ".hmy/keystore"
stakingRPC = "hmy_sendRawStakingTransaction"
)
type staker struct{}
var (
queryID = 0
s = &staker{}
localNetChain = big.NewInt(2)
dAddr = common.ParseAddr(testAccount)
)
const (
// Harmony protocol assume beacon chain shard is only place to send
// staking, later need to consider logic when beacon chain shard rotates
stakingShard = 0
testAccount = "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9"
testBLSPubKey = "b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611"
testAccountPassword = ""
)
func (s *staker) run(cmd *cobra.Command, args []string) error {
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
ks := keystore.NewKeyStore(keystoreDir, scryptN, scryptP)
account := accounts.Account{Address: dAddr}
ks.Unlock(account, testAccountPassword)
gasPrice := big.NewInt(0)
stakePayloadMaker := func() (staking.Directive, interface{}) {
p := &bls.PublicKey{}
p.DeserializeHexStr(testBLSPubKey)
pub := shard.BlsPublicKey{}
pub.FromLibBLSPublicKey(p)
return staking.DirectiveNewValidator, staking.NewValidator{
Description: staking.Description{
Name: "something",
Identity: "something else",
Website: "some site, harmony.one",
SecurityContact: "mr.smith",
Details: "blah blah details",
},
CommissionRates: staking.CommissionRates{
Rate: staking.NewDec(100),
MaxRate: staking.NewDec(150),
MaxChangeRate: staking.NewDec(5),
},
MinSelfDelegation: big.NewInt(10),
StakingAddress: common.Address(dAddr),
PubKey: pub,
Amount: big.NewInt(100),
}
// return message.DirectiveDelegate, message.Delegate{
// common.Address(dAddr),
// common.Address(dAddr),
// big.NewInt(10),
// }
}
stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker)
if err != nil {
return err
}
signed, oops := ks.SignStakingTx(account, stakingTx, localNetChain)
if oops != nil {
return oops
}
enc, oops1 := rlp.EncodeToBytes(signed)
if oops1 != nil {
return oops1
}
tx := new(staking.StakingTransaction)
if err := rlp.DecodeBytes(enc, tx); err != nil {
return err
}
fmt.Printf("In Client side: %+v\n", tx)
// return nil
rlp.DecodeBytes(enc, tx)
hexSignature := hexutil.Encode(enc)
param := []interface{}{hexSignature}
result, reqOops := baseRequest(stakingRPC, "http://localhost:9500", param)
fmt.Println(string(result))
return reqOops
}
func versionS() string {
return fmt.Sprintf(
"Harmony (C) 2019. %v, version %v-%v (%v %v)",
path.Base(os.Args[0]), version, commit, builtBy, builtAt,
)
}
func (s *staker) preRunInit(cmd *cobra.Command, args []string) error {
// Just in case need to do some kind of setup that needs to propagate downward
return nil
}
func baseRequest(method, node string, params interface{}) ([]byte, error) {
requestBody, _ := json.Marshal(map[string]interface{}{
"jsonrpc": "2.0",
"id": strconv.Itoa(queryID),
"method": method,
"params": params,
})
resp, err := http.Post(node, "application/json", bytes.NewBuffer(requestBody))
fmt.Printf("URL: %s, Request Body: %s\n\n", node, string(requestBody))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
queryID++
fmt.Printf("URL: %s, Response Body: %s\n\n", node, string(body))
return body, err
}
func init() {
rootCmd.AddCommand(&cobra.Command{
Use: "staking-iterate",
Short: "run through staking process",
PersistentPreRunE: s.preRunInit,
RunE: s.run,
})
rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Show version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(os.Stderr, versionS()+"\n")
os.Exit(0)
},
})
}
var (
rootCmd = &cobra.Command{
Use: "staking-standalone",
SilenceUsage: true,
Long: "testing staking quickly",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
)

@ -5,6 +5,7 @@ import (
"time"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
)
@ -28,7 +29,7 @@ type MessageSender struct {
// MessageRetry controls the message that can be retried
type MessageRetry struct {
blockNum uint64 // The block number this message is for
groups []p2p.GroupID
groups []nodeconfig.GroupID
p2pMsg []byte
msgType msg_pb.MessageType
retryCount int
@ -58,7 +59,7 @@ func (sender *MessageSender) Reset(blockNum uint64) {
}
// SendWithRetry sends message with retry logic.
func (sender *MessageSender) SendWithRetry(blockNum uint64, msgType msg_pb.MessageType, groups []p2p.GroupID, p2pMsg []byte) error {
func (sender *MessageSender) SendWithRetry(blockNum uint64, msgType msg_pb.MessageType, groups []nodeconfig.GroupID, p2pMsg []byte) error {
willRetry := sender.retryTimes != 0
msgRetry := MessageRetry{blockNum: blockNum, groups: groups, p2pMsg: p2pMsg, msgType: msgType, retryCount: 0, isActive: willRetry}
if willRetry {
@ -71,7 +72,7 @@ func (sender *MessageSender) SendWithRetry(blockNum uint64, msgType msg_pb.Messa
}
// SendWithoutRetry sends message without retry logic.
func (sender *MessageSender) SendWithoutRetry(groups []p2p.GroupID, p2pMsg []byte) error {
func (sender *MessageSender) SendWithoutRetry(groups []nodeconfig.GroupID, p2pMsg []byte) error {
return sender.host.SendMessageToGroups(groups, p2pMsg)
}

@ -19,9 +19,9 @@ import (
"github.com/harmony-one/harmony/core/types"
vrf_bls "github.com/harmony-one/harmony/crypto/vrf/bls"
"github.com/harmony-one/harmony/internal/chain"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
@ -134,9 +134,9 @@ func (consensus *Consensus) announce(block *types.Block) {
// Construct broadcast p2p message
if err := consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_ANNOUNCE, []p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
if err := consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_ANNOUNCE, []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
utils.Logger().Warn().
Str("groupID", string(p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID)))).
Str("groupID", string(nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)))).
Msg("[Announce] Cannot send announce message")
} else {
utils.Logger().Info().
@ -235,7 +235,7 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) {
logMsgs := consensus.PbftLog.GetMessagesByTypeSeqView(msg_pb.MessageType_ANNOUNCE, recvMsg.BlockNum, recvMsg.ViewID)
if len(logMsgs) > 0 {
if logMsgs[0].BlockHash != recvMsg.BlockHash {
if logMsgs[0].BlockHash != recvMsg.BlockHash && logMsgs[0].SenderPubkey.IsEqual(recvMsg.SenderPubkey) {
utils.Logger().Debug().
Str("leaderKey", consensus.LeaderPubKey.SerializeToHexStr()).
Msg("[OnAnnounce] Leader is malicious")
@ -284,7 +284,7 @@ func (consensus *Consensus) prepare() {
msgToSend := consensus.constructPrepareMessage()
// TODO: this will not return immediatey, may block
if err := consensus.msgSender.SendWithoutRetry([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
if err := consensus.msgSender.SendWithoutRetry([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
utils.Logger().Warn().Err(err).Msg("[OnAnnounce] Cannot send prepare message")
} else {
utils.Logger().Info().
@ -408,7 +408,7 @@ func (consensus *Consensus) onPrepare(msg *msg_pb.Message) {
return
}
if err := consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_PREPARED, []p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
if err := consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_PREPARED, []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
utils.Logger().Warn().Msg("[OnPrepare] Cannot send prepared message")
} else {
utils.Logger().Debug().
@ -592,7 +592,7 @@ func (consensus *Consensus) onPrepared(msg *msg_pb.Message) {
time.Sleep(consensus.delayCommit)
}
if err := consensus.msgSender.SendWithoutRetry([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
if err := consensus.msgSender.SendWithoutRetry([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
utils.Logger().Warn().Msg("[OnPrepared] Cannot send commit message!!")
} else {
utils.Logger().Info().
@ -771,7 +771,7 @@ func (consensus *Consensus) finalizeCommits() {
}
// if leader success finalize the block, send committed message to validators
if err := consensus.msgSender.SendWithRetry(block.NumberU64(), msg_pb.MessageType_COMMITTED, []p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
if err := consensus.msgSender.SendWithRetry(block.NumberU64(), msg_pb.MessageType_COMMITTED, []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend)); err != nil {
utils.Logger().Warn().Err(err).Msg("[Finalizing] Cannot send committed message")
} else {
utils.Logger().Info().

@ -10,8 +10,8 @@ import (
"github.com/harmony-one/bls/ffi/go/bls"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
@ -187,7 +187,7 @@ func (consensus *Consensus) startViewChange(viewID uint64) {
Msg("[startViewChange]")
msgToSend := consensus.constructViewChangeMessage()
consensus.host.SendMessageToGroups([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
consensus.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
consensus.consensusTimeout[timeoutViewChange].SetDuration(duration)
consensus.consensusTimeout[timeoutViewChange].Start()
@ -223,6 +223,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
}
// TODO: if difference is only one, new leader can still propose the same committed block to avoid another view change
// TODO: new leader catchup without ignore view change message
if consensus.blockNum > recvMsg.BlockNum {
utils.Logger().Debug().
Uint64("MsgBlockNum", recvMsg.BlockNum).
@ -252,6 +253,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
consensus.vcLock.Lock()
defer consensus.vcLock.Unlock()
// TODO: remove NIL type message
// add self m1 or m2 type message signature and bitmap
_, ok1 := consensus.nilSigs[consensus.PubKey.SerializeToHexStr()]
_, ok2 := consensus.bhpSigs[consensus.PubKey.SerializeToHexStr()]
@ -432,7 +434,7 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) {
Int("payloadSize", len(consensus.m1Payload)).
Hex("M1Payload", consensus.m1Payload).
Msg("[onViewChange] Sent NewView Message")
consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_NEWVIEW, []p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
consensus.msgSender.SendWithRetry(consensus.blockNum, msg_pb.MessageType_NEWVIEW, []nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
consensus.viewID = recvMsg.ViewID
consensus.ResetViewChangeState()
@ -554,6 +556,7 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
}
// NewView message is verified, change state to normal consensus
// TODO: check magic number 32
if len(recvMsg.Payload) > 32 {
// Construct and send the commit message
blockNumHash := make([]byte, 8)
@ -562,7 +565,7 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
msgToSend := consensus.constructCommitMessage(commitPayload)
utils.Logger().Info().Msg("onNewView === commit")
consensus.host.SendMessageToGroups([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
consensus.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
utils.Logger().Debug().
Str("From", consensus.phase.String()).
Str("To", Commit.String()).

@ -16,7 +16,9 @@
package core
import "errors"
import (
"github.com/pkg/errors"
)
var (
// ErrKnownBlock is returned when a block to import is already known locally.
@ -35,4 +37,7 @@ var (
// ErrShardStateNotMatch is returned if the calculated shardState hash not equal that in the block header
ErrShardStateNotMatch = errors.New("shard state root hash not match")
// ErrInvalidChainID when ChainID of signer does not match that of running node
ErrInvalidChainID = errors.New("invalid chain id for signer")
)

@ -12,8 +12,8 @@ import (
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/vdf"
"github.com/harmony-one/harmony/crypto/vrf/p256"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
@ -81,7 +81,7 @@ func (dRand *DRand) init(epochBlock *types.Block) {
Hex("msg", msgToSend).
Str("leader.PubKey", dRand.leader.ConsensusPubKey.SerializeToHexStr()).
Msg("[DRG] sent init")
dRand.host.SendMessageToGroups([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(dRand.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
dRand.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(dRand.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
}
// ProcessMessageLeader dispatches messages for the leader to corresponding processors.

@ -3,8 +3,8 @@ package drand
import (
protobuf "github.com/golang/protobuf/proto"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
@ -59,5 +59,5 @@ func (dRand *DRand) processInitMessage(message *msg_pb.Message) {
msgToSend := dRand.constructCommitMessage(rand, proof)
// Send the commit message back to leader
dRand.host.SendMessageToGroups([]p2p.GroupID{p2p.NewGroupIDByShardID(p2p.ShardID(dRand.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
dRand.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(dRand.ShardID))}, host.ConstructP2pMessage(byte(17), msgToSend))
}

@ -54,6 +54,7 @@ require (
github.com/rs/zerolog v1.14.3
github.com/shirou/gopsutil v2.18.12+incompatible
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.3.0
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc

@ -21,6 +21,7 @@ import (
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
// APIBackend An implementation of internal/hmyapi/Backend. Full client.
@ -280,3 +281,11 @@ func (b *APIBackend) ResendCx(ctx context.Context, txID common.Hash) (uint64, bo
func (b *APIBackend) IsLeader() bool {
return b.hmy.nodeAPI.IsCurrentlyLeader()
}
// SendStakingTx adds a staking transaction
func (b *APIBackend) SendStakingTx(
ctx context.Context,
newStakingTx *staking.StakingTransaction) error {
b.hmy.nodeAPI.AddPendingStakingTransaction(newStakingTx)
return nil
}

@ -11,6 +11,7 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
staking "github.com/harmony-one/harmony/staking/types"
)
// Harmony implements the Harmony full node service.
@ -43,6 +44,7 @@ type Harmony struct {
// NodeAPI is the list of functions from node used to call rpc apis.
type NodeAPI interface {
AddPendingStakingTransaction(*staking.StakingTransaction)
AddPendingTransaction(newTx *types.Transaction)
Blockchain() *core.BlockChain
AccountManager() *accounts.Manager

@ -11,8 +11,6 @@ import (
"github.com/harmony-one/bls/ffi/go/bls"
p2p_crypto "github.com/libp2p/go-libp2p-crypto"
"github.com/harmony-one/harmony/p2p"
)
// Role defines a role of a node.
@ -67,21 +65,20 @@ var publicRPC bool // enable public RPC access
// ConfigType is the structure of all node related configuration variables
type ConfigType struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
beacon p2p.GroupID // the beacon group ID
group p2p.GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client p2p.GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet/txgen
isBeacon bool // whether this node is beacon node doing consensus or not
ShardID uint32 // ShardID of this node; TODO ek – reviisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
beacon GroupID // the beacon group ID
group GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet/txgen
isBeacon bool // whether this node is beacon node doing consensus or not
ShardID uint32 // ShardID of this node; TODO ek – reviisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
MetricsFlag bool // collect and upload metrics flag
PushgatewayIP string // metrics pushgateway prometheus ip
PushgatewayPort string // metrics pushgateway prometheus port
StringRole string
Host p2p.Host
StakingPriKey *ecdsa.PrivateKey
P2pPriKey p2p_crypto.PrivKey
ConsensusPriKey *bls.SecretKey
@ -90,9 +87,6 @@ type ConfigType struct {
// Database directory
DBDir string
SelfPeer p2p.Peer
Leader p2p.Peer
networkType NetworkType
}
@ -139,17 +133,17 @@ func (conf *ConfigType) String() string {
}
// SetBeaconGroupID set the groupID for beacon group
func (conf *ConfigType) SetBeaconGroupID(g p2p.GroupID) {
func (conf *ConfigType) SetBeaconGroupID(g GroupID) {
conf.beacon = g
}
// SetShardGroupID set the groupID for shard group
func (conf *ConfigType) SetShardGroupID(g p2p.GroupID) {
func (conf *ConfigType) SetShardGroupID(g GroupID) {
conf.group = g
}
// SetClientGroupID set the groupID for client group
func (conf *ConfigType) SetClientGroupID(g p2p.GroupID) {
func (conf *ConfigType) SetClientGroupID(g GroupID) {
conf.client = g
}
@ -199,12 +193,12 @@ func (conf *ConfigType) GetPushgatewayPort() string {
}
// GetBeaconGroupID returns the groupID for beacon group
func (conf *ConfigType) GetBeaconGroupID() p2p.GroupID {
func (conf *ConfigType) GetBeaconGroupID() GroupID {
return conf.beacon
}
// GetShardGroupID returns the groupID for shard group
func (conf *ConfigType) GetShardGroupID() p2p.GroupID {
func (conf *ConfigType) GetShardGroupID() GroupID {
return conf.group
}
@ -214,7 +208,7 @@ func (conf *ConfigType) GetShardID() uint32 {
}
// GetClientGroupID returns the groupID for client group
func (conf *ConfigType) GetClientGroupID() p2p.GroupID {
func (conf *ConfigType) GetClientGroupID() GroupID {
return conf.client
}

@ -2,8 +2,6 @@ package nodeconfig
import (
"testing"
"github.com/harmony-one/harmony/p2p"
)
func TestNodeConfigSingleton(t *testing.T) {
@ -13,14 +11,14 @@ func TestNodeConfigSingleton(t *testing.T) {
// get the singleton variable
c := GetShardConfig(Global)
c.SetBeaconGroupID(p2p.GroupIDBeacon)
c.SetBeaconGroupID(GroupIDBeacon)
d := GetShardConfig(Global)
g := d.GetBeaconGroupID()
if g != p2p.GroupIDBeacon {
t.Errorf("GetBeaconGroupID = %v, expected = %v", g, p2p.GroupIDBeacon)
if g != GroupIDBeacon {
t.Errorf("GetBeaconGroupID = %v, expected = %v", g, GroupIDBeacon)
}
}

@ -1,12 +1,8 @@
package p2p
package nodeconfig
import (
"context"
"fmt"
"io"
"strconv"
libp2p_peer "github.com/libp2p/go-libp2p-peer"
)
// GroupID is a multicast group ID.
@ -25,32 +21,50 @@ func (id GroupID) String() string {
// Const of group ID
const (
GroupIDBeacon GroupID = "harmony/0.0.1/node/beacon"
GroupIDBeaconClient GroupID = "harmony/0.0.1/client/beacon"
GroupIDShardPrefix GroupID = "harmony/0.0.1/node/shard/%s"
GroupIDShardClientPrefix GroupID = "harmony/0.0.1/client/shard/%s"
GroupIDGlobal GroupID = "harmony/0.0.1/node/global"
GroupIDGlobalClient GroupID = "harmony/0.0.1/node/global"
GroupIDUnknown GroupID = "B1acKh0lE"
GroupIDBeacon GroupID = "%s/0.0.1/node/beacon"
GroupIDBeaconClient GroupID = "%s/0.0.1/client/beacon"
GroupIDShardPrefix GroupID = "%s/0.0.1/node/shard/%s"
GroupIDShardClientPrefix GroupID = "%s/0.0.1/client/shard/%s"
GroupIDGlobal GroupID = "%s/0.0.1/node/global"
GroupIDGlobalClient GroupID = "%s/0.0.1/node/global"
GroupIDUnknown GroupID = "%s/B1acKh0lE"
)
// ShardID defines the ID of a shard
type ShardID uint32
func getNetworkPrefix(shardID ShardID) (netPre string) {
switch GetShardConfig(uint32(shardID)).GetNetworkType() {
case Mainnet:
netPre = "harmony"
case Testnet:
netPre = "hmy/testnet"
case Pangaea:
netPre = "hmy/pangaea"
case Devnet:
netPre = "hmy/devnet"
case Localnet:
netPre = "hmy/local"
default:
netPre = "hmy/misc"
}
return
}
// NewGroupIDByShardID returns a new groupID for a shard
func NewGroupIDByShardID(shardID ShardID) GroupID {
if shardID == 0 {
return GroupIDBeacon
return GroupID(fmt.Sprintf(GroupIDBeacon.String(), getNetworkPrefix(shardID)))
}
return GroupID(fmt.Sprintf(GroupIDShardPrefix.String(), strconv.Itoa(int(shardID))))
return GroupID(fmt.Sprintf(GroupIDShardPrefix.String(), getNetworkPrefix(shardID), strconv.Itoa(int(shardID))))
}
// NewClientGroupIDByShardID returns a new groupID for a shard's client
func NewClientGroupIDByShardID(shardID ShardID) GroupID {
if shardID == 0 {
return GroupIDBeaconClient
return GroupID(fmt.Sprintf(GroupIDBeaconClient.String(), getNetworkPrefix(shardID)))
}
return GroupID(fmt.Sprintf(GroupIDShardClientPrefix.String(), strconv.Itoa(int(shardID))))
return GroupID(fmt.Sprintf(GroupIDShardClientPrefix.String(), getNetworkPrefix(shardID), strconv.Itoa(int(shardID))))
}
// ActionType lists action on group
@ -88,12 +102,3 @@ type GroupAction struct {
func (g GroupAction) String() string {
return fmt.Sprintf("%s/%s", g.Name, g.Action)
}
// GroupReceiver is a multicast group message receiver interface.
type GroupReceiver interface {
// Close closes this receiver.
io.Closer
// Receive a message.
Receive(ctx context.Context) (msg []byte, sender libp2p_peer.ID, err error)
}

@ -1,4 +1,4 @@
package p2p
package nodeconfig
import "testing"

@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
@ -18,6 +17,7 @@ import (
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
// Backend interface provides the common API services (that are provided by
@ -72,6 +72,7 @@ type Backend interface {
// retrieve the blockHash using txID and add blockHash to CxPool for resending
ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)
IsLeader() bool
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
}
// GetAPIs returns all the APIs.

@ -58,7 +58,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash)
if block != nil {
return RPCMarshalBlock(block, false, false)
return RPCMarshalBlock(block, true, fullTx)
}
return nil, err
}

@ -2,7 +2,6 @@ package hmyapi
import (
"context"
"errors"
"strings"
"github.com/ethereum/go-ethereum/common"
@ -10,16 +9,20 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
)
// TxHistoryArgs is struct to make GetTransactionsHistory request
type TxHistoryArgs struct {
Address string `json:"address"`
Offset int `json:"offset"`
Page int `json:"page"`
Address string `json:"address"`
PageIndex int `json:"pageIndex"`
PageSize int `json:"pageSize"`
FullTx bool `json:"fullTx"`
}
// PublicTransactionPoolAPI exposes methods for the RPC interface
@ -34,25 +37,35 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa
}
// GetTransactionsHistory returns the list of transactions hashes that involve a particular address.
func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) ([]common.Hash, error) {
func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) {
address := args.Address
result := []common.Hash{}
if strings.HasPrefix(address, "one1") {
result, err := s.b.GetTransactionsHistory(address)
hashes, err := s.b.GetTransactionsHistory(address)
if err != nil {
return nil, err
}
return ReturnWithPagination(result, args), nil
result = ReturnWithPagination(hashes, args)
}
addr := internal_common.ParseAddr(address)
oneAddress, err := internal_common.AddressToBech32(addr)
if err != nil {
return nil, err
}
result, err := s.b.GetTransactionsHistory(oneAddress)
hashes, err := s.b.GetTransactionsHistory(oneAddress)
if err != nil {
return nil, err
}
return ReturnWithPagination(result, args), nil
result = ReturnWithPagination(hashes, args)
if !args.FullTx {
return map[string]interface{}{"transactions": result}, nil
}
txs := []*RPCTransaction{}
for _, hash := range result {
tx := s.GetTransactionByHash(ctx, hash)
txs = append(txs, tx)
}
return map[string]interface{}{"transactions": txs}, nil
}
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
@ -155,6 +168,23 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
return SubmitTransaction(ctx, s.b, signed)
}
// SendRawStakingTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
ctx context.Context, encodedTx hexutil.Bytes,
) (common.Hash, error) {
tx := new(staking.StakingTransaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
}
c := s.b.ChainConfig().ChainID
if tx.ChainID().Cmp(c) != 0 {
e := errors.Wrapf(core.ErrInvalidChainID, "current chain id:%s", c.String())
return common.Hash{}, e
}
return SubmitStakingTransaction(ctx, s.b, tx)
}
// SendRawTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
@ -162,8 +192,10 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
}
if tx.ChainID().Cmp(s.b.ChainConfig().ChainID) != 0 {
return common.Hash{}, errors.New("Incorrect chain ID. The current chain id: " + s.b.ChainConfig().ChainID.String())
c := s.b.ChainConfig().ChainID
if tx.ChainID().Cmp(c) != 0 {
e := errors.Wrapf(core.ErrInvalidChainID, "current chain id:%s", c.String())
return common.Hash{}, e
}
return SubmitTransaction(ctx, s.b, tx)
}
@ -187,15 +219,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainID())
}
from, _ := types.Sender(signer, tx)
fields := map[string]interface{}{
"blockHash": blockHash,
"blockNumber": hexutil.Uint64(blockNumber),
"transactionHash": hash,
"transactionIndex": hexutil.Uint64(index),
"from": from,
"to": tx.To(),
"shardID": tx.ShardID(),
"gasUsed": hexutil.Uint64(receipt.GasUsed),
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
@ -203,7 +231,19 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
"logs": receipt.Logs,
"logsBloom": receipt.Bloom,
}
from, _ := types.Sender(signer, tx)
fields["from"] = from
fields["to"] = ""
if tx.To() != nil {
fields["to"], err = internal_common.AddressToBech32(*tx.To())
if err != nil {
return nil, err
}
fields["from"], err = internal_common.AddressToBech32(from)
if err != nil {
return nil, err
}
}
// Assign receipt status or post state.
if len(receipt.PostState) > 0 {
fields["root"] = hexutil.Bytes(receipt.PostState)

@ -3,6 +3,7 @@ package hmyapi
import (
"encoding/hex"
"math/big"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
@ -10,7 +11,7 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
internal_common "github.com/harmony-one/harmony/internal/common"
)
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
@ -78,7 +79,7 @@ func newHeaderInformation(header *block.Header) *HeaderInformation {
sig := header.LastCommitSignature()
result.LastCommitSig = hex.EncodeToString(sig[:])
bechAddr, err := common2.AddressToBech32(header.Coinbase())
bechAddr, err := internal_common.AddressToBech32(header.Coinbase())
if err != nil {
bechAddr = header.Coinbase().Hex()
}
@ -101,13 +102,15 @@ func newRPCCXReceipt(cx *types.CXReceipt, blockHash common.Hash, blockNumber uin
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
}
fromAddr, err := common2.AddressToBech32(cx.From)
fromAddr, err := internal_common.AddressToBech32(cx.From)
if err != nil {
fromAddr = cx.From.Hex()
return nil
}
toAddr, err := common2.AddressToBech32(*cx.To)
if err != nil {
toAddr = (*cx.To).Hex()
toAddr := ""
if cx.To != nil {
if toAddr, err = internal_common.AddressToBech32(*cx.To); err != nil {
return nil
}
}
result.From = fromAddr
result.To = toAddr
@ -144,15 +147,20 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
result.TransactionIndex = hexutil.Uint(index)
}
fromAddr, err := common2.AddressToBech32(from)
fromAddr, err := internal_common.AddressToBech32(from)
if err != nil {
fromAddr = from.Hex()
return nil
}
toAddr, err := common2.AddressToBech32(*tx.To())
if err != nil {
toAddr = (*tx.To()).Hex()
toAddr := ""
if tx.To() != nil {
if toAddr, err = internal_common.AddressToBech32(*tx.To()); err != nil {
return nil
}
result.From = fromAddr
} else {
result.From = strings.ToLower(from.Hex())
}
result.From = fromAddr
result.To = toAddr
return result

@ -5,32 +5,37 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
staking "github.com/harmony-one/harmony/staking/types"
)
// defaultOffset is to have default pagination.
// defaultPageSize is to have default pagination.
const (
defaultOffset = 100
defaultPageSize = 100
)
// ReturnWithPagination returns result with pagination (offset, page in TxHistoryArgs).
func ReturnWithPagination(hashes []common.Hash, args TxHistoryArgs) []common.Hash {
offset := defaultOffset
page := args.Page
if args.Offset > 0 {
offset = args.Offset
pageSize := defaultPageSize
pageIndex := args.PageIndex
if args.PageSize > 0 {
pageSize = args.PageSize
}
if pageSize*pageIndex >= len(hashes) {
return make([]common.Hash, 0)
}
if offset*page+offset > len(hashes) {
return hashes[offset*page:]
if pageSize*pageIndex+pageSize > len(hashes) {
return hashes[pageSize*pageIndex:]
}
return hashes[offset*page : offset*page+offset]
return hashes[pageSize*pageIndex : pageSize*pageIndex+pageSize]
}
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
func SubmitTransaction(
ctx context.Context, b Backend, tx *types.Transaction,
) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err
}
@ -53,3 +58,14 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
}
return tx.Hash(), nil
}
// SubmitStakingTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitStakingTransaction(
ctx context.Context, b Backend, tx *staking.StakingTransaction,
) (common.Hash, error) {
if err := b.SendStakingTx(ctx, tx); err != nil {
return common.Hash{}, err
}
utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction")
return tx.Hash(), nil
}

@ -6,11 +6,7 @@ import (
"sync"
"time"
types2 "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/api/client"
clientService "github.com/harmony-one/harmony/api/client/service"
@ -28,12 +24,14 @@ import (
"github.com/harmony-one/harmony/internal/chain"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/shardchain"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/node/worker"
"github.com/harmony-one/harmony/p2p"
p2p_host "github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
// State is a state of a node.
@ -127,7 +125,7 @@ type Node struct {
pendingTxMutex sync.Mutex
recentTxsStats types.RecentTxsStats
pendingStakingTransactions map[common.Hash]*types2.StakingTransaction // All the staking transactions received but not yet processed for Consensus
pendingStakingTransactions map[common.Hash]*staking.StakingTransaction // All the staking transactions received but not yet processed for Consensus
pendingStakingTxMutex sync.Mutex
Worker *worker.Worker
@ -246,11 +244,11 @@ func (node *Node) Beaconchain() *core.BlockChain {
func (node *Node) tryBroadcast(tx *types.Transaction) {
msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx})
shardGroupID := p2p.NewGroupIDByShardID(p2p.ShardID(tx.ShardID()))
shardGroupID := nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(tx.ShardID()))
utils.Logger().Info().Str("shardGroupID", string(shardGroupID)).Msg("tryBroadcast")
for attempt := 0; attempt < NumTryBroadCast; attempt++ {
if err := node.host.SendMessageToGroups([]p2p.GroupID{shardGroupID}, p2p_host.ConstructP2pMessage(byte(0), msg)); err != nil && attempt < NumTryBroadCast {
if err := node.host.SendMessageToGroups([]nodeconfig.GroupID{shardGroupID}, p2p_host.ConstructP2pMessage(byte(0), msg)); err != nil && attempt < NumTryBroadCast {
utils.Logger().Error().Int("attempt", attempt).Msg("Error when trying to broadcast tx")
} else {
break
@ -275,7 +273,7 @@ func (node *Node) addPendingTransactions(newTxs types.Transactions) {
}
// Add new staking transactions to the pending staking transaction list.
func (node *Node) addPendingStakingTransactions(newStakingTxs types2.StakingTransactions) {
func (node *Node) addPendingStakingTransactions(newStakingTxs staking.StakingTransactions) {
txPoolLimit := core.ShardingSchedule.MaxTxPoolSizeLimit()
node.pendingStakingTxMutex.Lock()
for _, tx := range newStakingTxs {
@ -290,6 +288,12 @@ func (node *Node) addPendingStakingTransactions(newStakingTxs types2.StakingTran
utils.Logger().Info().Int("length of newStakingTxs", len(newStakingTxs)).Int("totalPending", len(node.pendingTransactions)).Msg("Got more staking transactions")
}
// AddPendingStakingTransaction staking transactions
func (node *Node) AddPendingStakingTransaction(
newStakingTx *staking.StakingTransaction) {
node.addPendingStakingTransactions(staking.StakingTransactions{newStakingTx})
}
// AddPendingTransaction adds one new transaction to the pending transaction list.
// This is only called from SDK.
func (node *Node) AddPendingTransaction(newTx *types.Transaction) {
@ -326,7 +330,9 @@ func (node *Node) AddPendingReceipts(receipts *types.CXReceiptsProof) {
// Take out a subset of valid transactions from the pending transaction list
// Note the pending transaction list will then contain the rest of the txs
func (node *Node) getTransactionsForNewBlock(coinbase common.Address) (types.Transactions, types2.StakingTransactions) {
func (node *Node) getTransactionsForNewBlock(
coinbase common.Address,
) (types.Transactions, staking.StakingTransactions) {
txsThrottleConfig := core.ShardingSchedule.TxsThrottleConfig()
@ -347,7 +353,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) (types.Tra
utils.Logger().Error().
Err(err).
Msg("Failed updating worker's state before txn selection")
return types.Transactions{}, types2.StakingTransactions{}
return types.Transactions{}, staking.StakingTransactions{}
}
node.pendingTxMutex.Lock()
@ -356,7 +362,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) (types.Tra
defer node.pendingStakingTxMutex.Unlock()
pendingTransactions := types.Transactions{}
pendingStakingTransactions := types2.StakingTransactions{}
pendingStakingTransactions := staking.StakingTransactions{}
for _, tx := range node.pendingTransactions {
pendingTransactions = append(pendingTransactions, tx)
@ -378,7 +384,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) (types.Tra
Int("invalidDiscarded", len(invalid)).
Msg("Selecting Transactions")
node.pendingStakingTransactions = make(map[common.Hash]*types2.StakingTransaction)
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
for _, unselectedStakingTx := range unselectedStaking {
node.pendingStakingTransactions[unselectedStakingTx.Hash()] = unselectedStakingTx
}
@ -465,7 +471,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
node.pendingCXReceipts = make(map[string]*types.CXReceiptsProof)
node.pendingTransactions = make(map[common.Hash]*types.Transaction)
node.pendingStakingTransactions = make(map[common.Hash]*types2.StakingTransaction)
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
node.Consensus.VerifiedNewBlock = make(chan *types.Block)
// the sequence number is the next block number to be added in consensus protocol, which is always one more than current chain header block
@ -604,15 +610,15 @@ func (node *Node) initNodeConfiguration() (service.NodeConfig, chan p2p.Peer) {
PushgatewayIP: node.NodeConfig.GetPushgatewayIP(),
PushgatewayPort: node.NodeConfig.GetPushgatewayPort(),
IsClient: node.NodeConfig.IsClient(),
Beacon: p2p.GroupIDBeacon,
Beacon: nodeconfig.NewGroupIDByShardID(0),
ShardGroupID: node.NodeConfig.GetShardGroupID(),
Actions: make(map[p2p.GroupID]p2p.ActionType),
Actions: make(map[nodeconfig.GroupID]nodeconfig.ActionType),
}
if nodeConfig.IsClient {
nodeConfig.Actions[p2p.GroupIDBeaconClient] = p2p.ActionStart
nodeConfig.Actions[nodeconfig.NewClientGroupIDByShardID(0)] = nodeconfig.ActionStart
} else {
nodeConfig.Actions[node.NodeConfig.GetShardGroupID()] = p2p.ActionStart
nodeConfig.Actions[node.NodeConfig.GetShardGroupID()] = nodeconfig.ActionStart
}
var err error
@ -621,7 +627,7 @@ func (node *Node) initNodeConfiguration() (service.NodeConfig, chan p2p.Peer) {
utils.Logger().Error().Err(err).Msg("Failed to create shard receiver")
}
node.globalGroupReceiver, err = node.host.GroupReceiver(p2p.GroupIDBeaconClient)
node.globalGroupReceiver, err = node.host.GroupReceiver(nodeconfig.NewClientGroupIDByShardID(0))
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to create global receiver")
}

@ -4,7 +4,6 @@ import (
"encoding/binary"
"errors"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/ethereum/go-ethereum/common"
@ -17,6 +16,7 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
)
@ -68,8 +68,8 @@ func (node *Node) BroadcastCXReceiptsWithShardID(block *types.Block, commitSig [
}
utils.Logger().Info().Uint32("ToShardID", toShardID).Msg("[BroadcastCXReceiptsWithShardID] ReadCXReceipts and MerkleProof Found")
groupID := p2p.ShardID(toShardID)
go node.host.SendMessageToGroups([]p2p.GroupID{p2p.NewGroupIDByShardID(groupID)}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCXReceiptsProof(cxReceipts, merkleProof, block.Header(), commitSig, commitBitmap)))
groupID := nodeconfig.ShardID(toShardID)
go node.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(groupID)}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCXReceiptsProof(cxReceipts, merkleProof, block.Header(), commitSig, commitBitmap)))
}
// BroadcastMissingCXReceipts broadcasts missing cross shard receipts per request

@ -9,16 +9,11 @@ import (
"sync/atomic"
"time"
types2 "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
pb "github.com/golang/protobuf/proto"
"github.com/harmony-one/bls/ffi/go/bls"
libp2p_peer "github.com/libp2p/go-libp2p-peer"
"github.com/harmony-one/harmony/api/proto"
proto_discovery "github.com/harmony-one/harmony/api/proto/discovery"
"github.com/harmony-one/harmony/api/proto/message"
@ -32,6 +27,8 @@ import (
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
libp2p_peer "github.com/libp2p/go-libp2p-peer"
)
const (
@ -244,7 +241,7 @@ func (node *Node) transactionMessageHandler(msgPayload []byte) {
}
func (node *Node) stakingMessageHandler(msgPayload []byte) {
txs := types2.StakingTransactions{}
txs := staking.StakingTransactions{}
err := rlp.Decode(bytes.NewReader(msgPayload[:]), &txs)
if err != nil {
utils.Logger().Error().
@ -259,7 +256,7 @@ func (node *Node) stakingMessageHandler(msgPayload []byte) {
// NOTE: For now, just send to the client (basically not broadcasting)
// TODO (lc): broadcast the new blocks to new nodes doing state sync
func (node *Node) BroadcastNewBlock(newBlock *types.Block) {
groups := []p2p.GroupID{node.NodeConfig.GetClientGroupID()}
groups := []nodeconfig.GroupID{node.NodeConfig.GetClientGroupID()}
utils.Logger().Info().Msgf("broadcasting new block %d, group %s", newBlock.NumberU64(), groups[0])
msg := host.ConstructP2pMessage(byte(0), proto_node.ConstructBlocksSyncMessage([]*types.Block{newBlock}))
if err := node.host.SendMessageToGroups(groups, msg); err != nil {
@ -303,7 +300,7 @@ func (node *Node) BroadcastCrossLinkHeader(newBlock *types.Block) {
for _, header := range headers {
utils.Logger().Debug().Msgf("[BroadcastCrossLinkHeader] Broadcasting %d", header.Number().Uint64())
}
node.host.SendMessageToGroups([]p2p.GroupID{node.NodeConfig.GetBeaconGroupID()}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCrossLinkHeadersMessage(headers)))
node.host.SendMessageToGroups([]nodeconfig.GroupID{node.NodeConfig.GetBeaconGroupID()}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCrossLinkHeadersMessage(headers)))
}
// VerifyNewBlock is called by consensus participants to verify the block (account model) they are running consensus on

@ -6,7 +6,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/ctxerror"

@ -20,9 +20,9 @@ import (
proto_node "github.com/harmony-one/harmony/api/proto/node"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/shard"
)
@ -141,7 +141,7 @@ func (node *Node) broadcastEpochShardState(newBlock *types.Block) error {
},
)
return node.host.SendMessageToGroups(
[]p2p.GroupID{node.NodeConfig.GetClientGroupID()},
[]nodeconfig.GroupID{node.NodeConfig.GetClientGroupID()},
host.ConstructP2pMessage(byte(0), epochShardStateMessage))
}

@ -14,7 +14,6 @@ import (
"github.com/harmony-one/harmony/api/service/networkinfo"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
)
func (node *Node) setupForValidator() {
@ -59,7 +58,7 @@ func (node *Node) setupForNewNode() {
func (node *Node) setupForClientNode() {
// Register networkinfo service. "0" is the beacon shard ID
node.serviceManager.RegisterService(service.NetworkInfo, networkinfo.MustNew(node.host, p2p.GroupIDBeacon, nil, nil, node.networkInfoDHTPath()))
node.serviceManager.RegisterService(service.NetworkInfo, networkinfo.MustNew(node.host, nodeconfig.NewGroupIDByShardID(0), nil, nil, node.networkInfoDHTPath()))
}
func (node *Node) setupForExplorerNode() {
@ -109,8 +108,8 @@ func (node *Node) StopServices() {
func (node *Node) networkInfoDHTPath() string {
return fmt.Sprintf(".dht-%s-%s-c%s",
node.NodeConfig.SelfPeer.IP,
node.NodeConfig.SelfPeer.Port,
node.SelfPeer.IP,
node.SelfPeer.Port,
node.chainConfig.ChainID,
)
}

@ -5,27 +5,21 @@ import (
"math/big"
"time"
types2 "github.com/harmony-one/harmony/staking/types"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/shard"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
// environment is the worker's current environment and holds all of the current state information.
@ -150,9 +144,14 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
}
// SelectStakingTransactionsForNewBlock selects staking transactions for new block.
func (w *Worker) SelectStakingTransactionsForNewBlock(newBlockNum uint64, txs types2.StakingTransactions, recentTxsStats types.RecentTxsStats, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types2.StakingTransactions, types2.StakingTransactions, types2.StakingTransactions) {
func (w *Worker) SelectStakingTransactionsForNewBlock(
newBlockNum uint64, txs staking.StakingTransactions,
recentTxsStats types.RecentTxsStats,
txsThrottleConfig *shardingconfig.TxsThrottleConfig,
coinbase common.Address) (staking.StakingTransactions, staking.StakingTransactions, staking.StakingTransactions) {
// TODO: implement staking transaction selection
return types2.StakingTransactions{}, types2.StakingTransactions{}, types2.StakingTransactions{}
t := staking.StakingTransactions{}
return t, t, t
}
func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
@ -179,7 +178,8 @@ func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
}
// CommitTransactions commits transactions including staking transactions.
func (w *Worker) CommitTransactions(txs types.Transactions, stakingTxns types2.StakingTransactions, coinbase common.Address) error {
func (w *Worker) CommitTransactions(
txs types.Transactions, stakingTxns staking.StakingTransactions, coinbase common.Address) error {
// Must update to the correct current state before processing potential txns
if err := w.UpdateCurrent(coinbase); err != nil {
utils.Logger().Error().

@ -5,18 +5,16 @@ import (
"math/rand"
"testing"
types2 "github.com/harmony-one/harmony/staking/types"
blockfactory "github.com/harmony-one/harmony/block/factory"
chain2 "github.com/harmony-one/harmony/internal/chain"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
chain2 "github.com/harmony-one/harmony/internal/chain"
"github.com/harmony-one/harmony/internal/params"
staking "github.com/harmony-one/harmony/staking/types"
)
var (
@ -77,7 +75,7 @@ func TestCommitTransactions(t *testing.T) {
tx, _ := types.SignTx(types.NewTransaction(baseNonce, testBankAddress, uint32(0), big.NewInt(int64(denominations.One*randAmount)), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
// Commit the tx to the worker
err := worker.CommitTransactions(types.Transactions{tx}, types2.StakingTransactions{}, testBankAddress)
err := worker.CommitTransactions(types.Transactions{tx}, staking.StakingTransactions{}, testBankAddress)
if err != nil {
t.Error(err)
}

@ -1,6 +1,7 @@
package p2p
import (
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
libp2p_host "github.com/libp2p/go-libp2p-host"
libp2p_peer "github.com/libp2p/go-libp2p-peer"
)
@ -21,11 +22,11 @@ type Host interface {
ConnectHostPeer(Peer)
// SendMessageToGroups sends a message to one or more multicast groups.
SendMessageToGroups(groups []GroupID, msg []byte) error
SendMessageToGroups(groups []nodeconfig.GroupID, msg []byte) error
// GroupReceiver returns a receiver of messages sent to a multicast group.
// Each call creates a new receiver.
// If multiple receivers are created for the same group,
// a message sent to the group will be delivered to all of the receivers.
GroupReceiver(GroupID) (receiver GroupReceiver, err error)
GroupReceiver(nodeconfig.GroupID) (receiver GroupReceiver, err error)
}

@ -9,6 +9,7 @@ import (
"github.com/rs/zerolog"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
@ -54,7 +55,7 @@ type HostV2 struct {
}
// SendMessageToGroups sends a message to one or more multicast groups.
func (host *HostV2) SendMessageToGroups(groups []p2p.GroupID, msg []byte) error {
func (host *HostV2) SendMessageToGroups(groups []nodeconfig.GroupID, msg []byte) error {
var error error
for _, group := range groups {
err := host.pubsub.Publish(string(group), msg)
@ -100,7 +101,7 @@ func (r *GroupReceiverImpl) Receive(ctx context.Context) (
// GroupReceiver returns a receiver of messages sent to a multicast group.
// See the GroupReceiver interface for details.
func (host *HostV2) GroupReceiver(group p2p.GroupID) (
func (host *HostV2) GroupReceiver(group nodeconfig.GroupID) (
receiver p2p.GroupReceiver, err error,
) {
sub, err := host.pubsub.Subscribe(string(group))

@ -11,7 +11,7 @@ import (
libp2p_pubsub "github.com/libp2p/go-libp2p-pubsub"
libp2p_pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/harmony-one/harmony/p2p"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
mock "github.com/harmony-one/harmony/p2p/host/hostv2/mock"
)
@ -19,7 +19,7 @@ func TestHostV2_SendMessageToGroups(t *testing.T) {
t.Run("Basic", func(t *testing.T) {
mc := gomock.NewController(t)
defer mc.Finish()
groups := []p2p.GroupID{"ABC", "DEF"}
groups := []nodeconfig.GroupID{"ABC", "DEF"}
data := []byte{1, 2, 3}
pubsub := mock.NewMockpubsub(mc)
gomock.InOrder(
@ -34,7 +34,7 @@ func TestHostV2_SendMessageToGroups(t *testing.T) {
t.Run("Error", func(t *testing.T) {
mc := gomock.NewController(t)
defer mc.Finish()
groups := []p2p.GroupID{"ABC", "DEF"}
groups := []nodeconfig.GroupID{"ABC", "DEF"}
data := []byte{1, 2, 3}
pubsub := mock.NewMockpubsub(mc)
gomock.InOrder(

@ -6,6 +6,7 @@ package mock_p2p
import (
gomock "github.com/golang/mock/gomock"
node "github.com/harmony-one/harmony/internal/configs/node"
p2p "github.com/harmony-one/harmony/p2p"
go_libp2p_host "github.com/libp2p/go-libp2p-host"
go_libp2p_peer "github.com/libp2p/go-libp2p-peer"
@ -132,7 +133,7 @@ func (mr *MockHostMockRecorder) ConnectHostPeer(arg0 interface{}) *gomock.Call {
}
// SendMessageToGroups mocks base method
func (m *MockHost) SendMessageToGroups(groups []p2p.GroupID, msg []byte) error {
func (m *MockHost) SendMessageToGroups(groups []node.GroupID, msg []byte) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendMessageToGroups", groups, msg)
ret0, _ := ret[0].(error)
@ -146,7 +147,7 @@ func (mr *MockHostMockRecorder) SendMessageToGroups(groups, msg interface{}) *go
}
// GroupReceiver mocks base method
func (m *MockHost) GroupReceiver(arg0 p2p.GroupID) (p2p.GroupReceiver, error) {
func (m *MockHost) GroupReceiver(arg0 node.GroupID) (p2p.GroupReceiver, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GroupReceiver", arg0)
ret0, _ := ret[0].(p2p.GroupReceiver)

@ -1,7 +1,9 @@
package p2p
import (
"context"
"fmt"
"io"
"net"
"github.com/harmony-one/bls/ffi/go/bls"
@ -28,3 +30,12 @@ func (p Peer) String() string {
}
return fmt.Sprintf("BlsPubKey:%s-%s/%s[%d]", BlsPubKey, net.JoinHostPort(p.IP, p.Port), p.PeerID, len(p.Addrs))
}
// GroupReceiver is a multicast group message receiver interface.
type GroupReceiver interface {
// Close closes this receiver.
io.Closer
// Receive a message.
Receive(ctx context.Context) (msg []byte, sender libp2p_peer.ID, err error)
}

@ -8,6 +8,7 @@ SRC[txgen]=cmd/client/txgen/main.go
SRC[bootnode]=cmd/bootnode/main.go
SRC[wallet]="cmd/client/wallet/main.go cmd/client/wallet/generated_wallet.ini.go"
SRC[wallet_stress_test]="cmd/client/wallet_stress_test/main.go cmd/client/wallet_stress_test/generated_wallet.ini.go"
SRC[staking-standalone]='cmd/staking/*.go'
BINDIR=bin
BUCKET=unique-bucket-bin
@ -106,10 +107,10 @@ function build_only
env GOOS=$GOOS GOARCH=$GOARCH go build $VERBOSE -gcflags="all=-c 2" -ldflags="-X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.builtAt=${BUILTAT} -X main.builtBy=${BUILTBY}" -o $BINDIR/$bin $RACE ${SRC[$bin]}
fi
if [ "$(uname -s)" == "Linux" ]; then
$BINDIR/$bin -version
$BINDIR/$bin -version || $BINDIR/$bin version
fi
if [ "$(uname -s)" == "Darwin" -a "$GOOS" == "darwin" -a -e $BINDIR/$bin ]; then
$BINDIR/$bin -version
$BINDIR/$bin -version || $BINDIR/$bin version
fi
fi
done
@ -256,6 +257,6 @@ case "$ACTION" in
"upload") upload ;;
"release") release ;;
"pubwallet") upload_wallet ;;
"harmony"|"wallet"|"txgen"|"bootnode") build_only $ACTION ;;
"harmony"|"wallet"|"txgen"|"bootnode"|"staking-standalone") build_only $ACTION ;;
*) usage ;;
esac

@ -8,7 +8,8 @@ type (
// Commission defines a commission parameters for a given validator.
Commission struct {
CommissionRates `json:"commission_rates" yaml:"commission_rates"`
UpdateHeight *big.Int `json:"update_time" yaml:"update_time"` // the block height the commission rate was last changed
UpdateHeight *big.Int `json:"update_height" yaml:"update_height"` // the block height the commission rate was last changed
}
// CommissionRates defines the initial commission rates to be used for creating a
@ -19,3 +20,9 @@ type (
MaxChangeRate Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum increase of the validator commission every epoch, as a fraction
}
)
// NewCommission returns a new commission object
func NewCommission(rate Dec, maxRate Dec, maxChangeRate Dec, height *big.Int) Commission {
commissionRates := CommissionRates{Rate: rate, MaxRate: maxRate, MaxChangeRate: maxChangeRate}
return Commission{CommissionRates: commissionRates, UpdateHeight: height}
}

@ -5,7 +5,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -0,0 +1,247 @@
package types
import (
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/internal/common"
)
// DVPair is struct that just has a delegator-validator pair with no other data.
// It is intended to be used as a marshalable pointer. For example, a DVPair can be used to construct the
// key to getting an UnbondingDelegation from state.
type DVPair struct {
DelegatorAddress common.Address
ValidatorAddress common.Address
}
// DVVTriplet is struct that just has a delegator-validator-validator triplet with no other data.
// It is intended to be used as a marshalable pointer. For example, a DVVTriplet can be used to construct the
// key to getting a Redelegation from state.
type DVVTriplet struct {
DelegatorAddress common.Address
ValidatorSrcAddress common.Address
ValidatorDstAddress common.Address
}
// Delegation represents the bond with tokens held by an account. It is
// owned by one delegator, and is associated with the voting power of one
// validator.
type Delegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewDelegation creates a new delegation object
func NewDelegation(delegatorAddr common.Address, validatorAddr common.Address,
amount *big.Int) Delegation {
return Delegation{
DelegatorAddress: delegatorAddr,
ValidatorAddress: validatorAddr,
Amount: amount,
}
}
// MarshalDelegation return the delegation
func MarshalDelegation(delegation Delegation) ([]byte, error) {
return rlp.EncodeToBytes(delegation)
}
// UnmarshalDelegation return the delegation
func UnmarshalDelegation(by []byte) (*Delegation, error) {
decoded := &Delegation{}
err := rlp.DecodeBytes(by, decoded)
return decoded, err
}
// GetDelegatorAddr returns DelegatorAddr
func (d Delegation) GetDelegatorAddr() common.Address { return d.DelegatorAddress }
// GetValidatorAddr returns ValidatorAddr
func (d Delegation) GetValidatorAddr() common.Address { return d.ValidatorAddress }
// GetAmount returns amount of a delegation
func (d Delegation) GetAmount() *big.Int { return d.Amount }
// String returns a human readable string representation of a Delegation.
func (d Delegation) String() string {
return fmt.Sprintf(`Delegation:
Delegator: %s
Validator: %s
Amount: %s`, d.DelegatorAddress,
d.ValidatorAddress, d.Amount)
}
// Delegations is a collection of delegations
type Delegations []Delegation
// String returns the string representation of a list of delegations
func (d Delegations) String() (out string) {
for _, del := range d {
out += del.String() + "\n"
}
return strings.TrimSpace(out)
}
// UnbondingDelegation stores all of a single delegator's unbonding bonds
// for a single validator in an time-ordered list
type UnbondingDelegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"` // validator unbonding from operator addr
Entries []UnbondingDelegationEntry `json:"entries" yaml:"entries"` // unbonding delegation entries
}
// UnbondingDelegationEntry - entry to an UnbondingDelegation
type UnbondingDelegationEntry struct {
ExitEpoch *big.Int `json:"exit_epoch" yaml:"exit_epoch"` // epoch which the unbonding begins
Amount *big.Int `json:"amount" yaml:"amount"` // atoms to receive at completion
}
// NewUnbondingDelegation - create a new unbonding delegation object
func NewUnbondingDelegation(delegatorAddr common.Address,
validatorAddr common.Address, epoch *big.Int, amt *big.Int) UnbondingDelegation {
entry := NewUnbondingDelegationEntry(epoch, amt)
return UnbondingDelegation{
DelegatorAddress: delegatorAddr,
ValidatorAddress: validatorAddr,
Entries: []UnbondingDelegationEntry{entry},
}
}
// NewUnbondingDelegationEntry - create a new unbonding delegation object
func NewUnbondingDelegationEntry(epoch *big.Int, amt *big.Int) UnbondingDelegationEntry {
return UnbondingDelegationEntry{
ExitEpoch: epoch,
Amount: amt,
}
}
// AddEntry - append entry to the unbonding delegation
// if there exists same ExitEpoch entry, merge the amount
// TODO: check the total amount not exceed the staking amount call this function
func (d *UnbondingDelegation) AddEntry(epoch *big.Int, amt *big.Int) {
entry := NewUnbondingDelegationEntry(epoch, amt)
for i := range d.Entries {
if d.Entries[i].ExitEpoch == entry.ExitEpoch {
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount)
return
}
}
// same exit epoch entry not found
d.Entries = append(d.Entries, entry)
return
}
// String returns a human readable string representation of an UnbondingDelegation.
func (d UnbondingDelegation) String() string {
out := fmt.Sprintf(`Unbonding Delegations between:
Delegator: %s
Validator: %s
Entries:`, d.DelegatorAddress, d.ValidatorAddress)
for i, entry := range d.Entries {
out += fmt.Sprintf(` Unbonding Delegation %d:
ExitEpoch: %v
Amount: %s`, i, entry.ExitEpoch, entry.Amount)
}
return out
}
// UnbondingDelegations is a collection of UnbondingDelegation
type UnbondingDelegations []UnbondingDelegation
func (ubds UnbondingDelegations) String() (out string) {
for _, u := range ubds {
out += u.String() + "\n"
}
return strings.TrimSpace(out)
}
// Redelegation contains the list of a particular delegator's
// redelegating bonds from a particular source validator to a
// particular destination validator
type Redelegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
ValidatorSrcAddress common.Address `json:"validator_src_address" yaml:"validator_src_address"` // validator redelegation source operator addr
ValidatorDstAddress common.Address `json:"validator_dst_address" yaml:"validator_dst_address"` // validator redelegation destination operator addr
Entries []RedelegationEntry `json:"entries" yaml:"entries"` // redelegation entries
}
// RedelegationEntry - entry to a Redelegation
type RedelegationEntry struct {
Epoch *big.Int `json:"epoch" yaml:"epoch"` // epoch at which the redelegation took place
Amount *big.Int `json:"amount" yaml:"amount"` // amount of destination-validator tokens created by redelegation
}
// NewRedelegation - create a new redelegation object
func NewRedelegation(delegatorAddr common.Address, validatorSrcAddr,
validatorDstAddr common.Address, epoch *big.Int, amt *big.Int) Redelegation {
entry := NewRedelegationEntry(epoch, amt)
return Redelegation{
DelegatorAddress: delegatorAddr,
ValidatorSrcAddress: validatorSrcAddr,
ValidatorDstAddress: validatorDstAddr,
Entries: []RedelegationEntry{entry},
}
}
// NewRedelegationEntry - create a new redelegation object
func NewRedelegationEntry(epoch *big.Int, amt *big.Int) RedelegationEntry {
return RedelegationEntry{
Epoch: epoch,
Amount: amt,
}
}
// AddEntry - append entry to the unbonding delegation
// Merge if has same epoch field
func (d *Redelegation) AddEntry(epoch *big.Int, amt *big.Int) {
entry := NewRedelegationEntry(epoch, amt)
for i := range d.Entries {
if d.Entries[i].Epoch == entry.Epoch {
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount)
return
}
}
// same epoch entry not found
d.Entries = append(d.Entries, entry)
return
}
// String returns a human readable string representation of a Redelegation.
func (d Redelegation) String() string {
out := fmt.Sprintf(`Redelegations between:
Delegator: %s
Source Validator: %s
Destination Validator: %s
Entries:
`,
d.DelegatorAddress, d.ValidatorSrcAddress, d.ValidatorDstAddress,
)
for i, entry := range d.Entries {
out += fmt.Sprintf(` Redelegation Entry #%d:
Epoch: %v
Amount: %v
`,
i, entry.Epoch, entry.Amount,
)
}
return strings.TrimRight(out, "\n")
}
// Redelegations are a collection of Redelegation
type Redelegations []Redelegation
func (d Redelegations) String() (out string) {
for _, red := range d {
out += red.String() + "\n"
}
return strings.TrimSpace(out)
}

@ -1,231 +1,77 @@
package types
import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
"github.com/pkg/errors"
)
// Directive says what kind of payload follows
type Directive byte
const (
// CreateValidator ...
CreateValidator = "create_validator"
// EditValidator ...
EditValidator = "edit_validator"
// Delegate ...
Delegate = "delegate"
// Redelegate ...
Redelegate = "redelegate"
// Undelegate ...
Undelegate = "undelegate"
// DirectiveNewValidator ...
DirectiveNewValidator Directive = iota
// DirectiveEditValidator ...
DirectiveEditValidator
// DirectiveDelegate ...
DirectiveDelegate
// DirectiveRedelegate ...
DirectiveRedelegate
// DirectiveUndelegate ...
DirectiveUndelegate
)
// StakingMessage must fulfill these interfaces
type StakingMessage interface {
// Type returns a human-readable string for the type of the staking message
Type() string
// Signer returns the ECDSA address who must sign the outer transaction
Signer() common.Address
}
var (
directiveKind = [...]string{
"NewValidator", "EditValidator", "Delegate", "Redelegate", "Undelegate",
}
// ErrInvalidStakingKind given when caller gives bad staking message kind
ErrInvalidStakingKind = errors.New("bad staking kind")
)
// MsgCreateValidator - struct for creating a new validator
type MsgCreateValidator struct {
Description Description `json:"description" yaml:"description"`
Commission CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
ValidatingPubKey shard.BlsPublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Amount *big.Int `json:"amount" yaml:"amount"`
func (d Directive) String() string {
return directiveKind[d]
}
// msgCreateValidatorJSON - struct for creating a new validator for JSON
type msgCreateValidatorJSON struct {
Description Description `json:"description" yaml:"description"`
Commission CommissionRates `json:"commission" yaml:"commission"`
// NewValidator - type for creating a new validator
type NewValidator struct {
Description `json:"ties" yaml:"ties"`
CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
ValidatingPubKey shard.BlsPublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
PubKey shard.BlsPublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgCreateValidator creates a new validator
func NewMsgCreateValidator(
description Description, commission CommissionRates, minSelfDelegation *big.Int, stakingAddress common.Address, validatingPubKey shard.BlsPublicKey, amount *big.Int) MsgCreateValidator {
return MsgCreateValidator{
Description: description,
Commission: commission,
MinSelfDelegation: minSelfDelegation,
StakingAddress: stakingAddress,
ValidatingPubKey: validatingPubKey,
Amount: amount,
}
}
// Type ...
func (msg MsgCreateValidator) Type() string { return CreateValidator }
// Signer ...
func (msg MsgCreateValidator) Signer() common.Address { return msg.StakingAddress }
// MarshalJSON implements the json.Marshaler interface to provide custom JSON
// serialization of the MsgCreateValidator type.
func (msg MsgCreateValidator) MarshalJSON() ([]byte, error) {
return json.Marshal(msgCreateValidatorJSON{
Description: msg.Description,
Commission: msg.Commission,
MinSelfDelegation: msg.MinSelfDelegation,
StakingAddress: msg.StakingAddress,
ValidatingPubKey: msg.ValidatingPubKey,
Amount: msg.Amount,
})
}
// UnmarshalJSON implements the json.Unmarshaler interface to provide custom
// JSON deserialization of the MsgCreateValidator type.
func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error {
var msgCreateValJSON msgCreateValidatorJSON
if err := json.Unmarshal(bz, &msgCreateValJSON); err != nil {
return err
}
msg.Description = msgCreateValJSON.Description
msg.Commission = msgCreateValJSON.Commission
msg.MinSelfDelegation = msgCreateValJSON.MinSelfDelegation
msg.StakingAddress = msgCreateValJSON.StakingAddress
msg.ValidatingPubKey = msgCreateValJSON.ValidatingPubKey
msg.Amount = msgCreateValJSON.Amount
return nil
}
// ValidateBasic quick validity check
func (msg MsgCreateValidator) ValidateBasic() error {
// note that unmarshaling from bech32 ensures either empty or valid
if msg.StakingAddress.Big().Uint64() == 0 {
return errors.New("[CreateValidator] address is empty")
}
if msg.ValidatingPubKey.IsEmpty() {
return errors.New("[CreateValidator] invalid BLS public key")
}
if msg.Description == (Description{}) {
return errors.New("[CreateValidator] description must be included")
}
if msg.Commission == (CommissionRates{}) {
return errors.New("[CreateValidator] commission must be included")
}
if msg.Amount.Cmp(msg.MinSelfDelegation) > 0 {
return errors.New("[CreateValidator] stake amount must be >= MinSelfDelegation")
}
return nil
}
// MsgEditValidator - struct for editing a validator
type MsgEditValidator struct {
// EditValidator - type for edit existing validator
type EditValidator struct {
Description
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
// MsgEditValidatorJSON - struct for editing a validator for JSON
type MsgEditValidatorJSON struct {
Description
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
// TODO: allow update of bls public key
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
// NewMsgEditValidator creates a new MsgEditValidator.
func NewMsgEditValidator(
description Description, stakingAddress common.Address, commissionRate Dec, minSelfDelegation *big.Int) MsgEditValidator {
return MsgEditValidator{
Description: description,
StakingAddress: stakingAddress,
CommissionRate: commissionRate,
MinSelfDelegation: minSelfDelegation,
}
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
// Type ...
func (msg MsgEditValidator) Type() string { return EditValidator }
// Signer ...
func (msg MsgEditValidator) Signer() common.Address { return msg.StakingAddress }
// MsgDelegate - struct for bonding transactions
type MsgDelegate struct {
// Delegate - type for delegating to a validator
type Delegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgDelegate creates a new MsgDelegate.
func NewMsgDelegate(
validatorAddress common.Address, delegatorAddress common.Address, amount *big.Int) MsgDelegate {
return MsgDelegate{
DelegatorAddress: delegatorAddress,
ValidatorAddress: validatorAddress,
Amount: amount,
}
}
// Type ...
func (msg MsgDelegate) Type() string { return Delegate }
// Signer ...
func (msg MsgDelegate) Signer() common.Address { return msg.DelegatorAddress }
// MsgRedelegate - struct for re-bonding transactions
type MsgRedelegate struct {
// Redelegate - type for reassigning delegation
type Redelegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorSrcAddress common.Address `json:"validator_src_address" yaml:"validator_src_address"`
ValidatorDstAddress common.Address `json:"validator_dst_address" yaml:"validator_dst_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgRedelegate creates a new MsgRedelegate.
func NewMsgRedelegate(delAddr, valSrcAddr, valDstAddr common.Address, amount *big.Int) MsgRedelegate {
return MsgRedelegate{
DelegatorAddress: delAddr,
ValidatorSrcAddress: valSrcAddr,
ValidatorDstAddress: valDstAddr,
Amount: amount,
}
}
// Type ...
func (msg MsgRedelegate) Type() string { return Redelegate }
// Signer ...
func (msg MsgRedelegate) Signer() common.Address { return msg.DelegatorAddress }
// MsgUndelegate - struct for unbonding transactions
type MsgUndelegate struct {
// Undelegate - type for removing delegation responsibility
type Undelegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgUndelegate creates a new MsgUndelegate.
func NewMsgUndelegate(delAddr common.Address, valAddr common.Address, amount *big.Int) MsgUndelegate {
return MsgUndelegate{
DelegatorAddress: delAddr,
ValidatorAddress: valAddr,
Amount: amount,
}
}
// Type ...
func (msg MsgUndelegate) Type() string { return Undelegate }
// Signer ...
func (msg MsgUndelegate) Signer() common.Address { return msg.DelegatorAddress }

@ -1,218 +1,207 @@
package types
import (
"math/big"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
)
var (
minSelfDelegation = big.NewInt(1000)
stakeAmount = big.NewInt(2000)
delegateAmount = big.NewInt(500)
validatorAddress = common.MustBech32ToAddress("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy")
validatorAddress2 = common.MustBech32ToAddress("one1d2rngmem4x2c6zxsjjz29dlah0jzkr0k2n88wc")
delegatorAddress = common.MustBech32ToAddress("one16qsd5ant9v94jrs89mruzx62h7ekcfxmduh2rx")
blsPubKey = bls.RandPrivateKey().GetPublicKey()
)
func TestMsgCreateValidatorRLP(t *testing.T) {
commissionRate := NewDecWithPrec(1, 2) // 10%
maxRate := NewDecWithPrec(2, 2) // 20%
maxChangeRate := NewDecWithPrec(1, 3) // 1%
blsPublickey := shard.BlsPublicKey{}
blsPublickey.FromLibBLSPublicKey(blsPubKey)
msgCreateValidator := NewMsgCreateValidator(Description{
Name: "validator 1",
Identity: "1",
Website: "harmony.one",
SecurityContact: "11.111.1111",
Details: "the best validator ever",
}, CommissionRates{
Rate: commissionRate,
MaxRate: maxRate,
MaxChangeRate: maxChangeRate,
}, minSelfDelegation, validatorAddress, blsPublickey, stakeAmount)
rlpBytes, err := rlp.EncodeToBytes(msgCreateValidator)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgCreateValidator{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if !decodedMsg.Commission.Rate.Equal(msgCreateValidator.Commission.Rate) {
t.Error("Commission rate does not match")
}
if !decodedMsg.Commission.MaxRate.Equal(msgCreateValidator.Commission.MaxRate) {
t.Error("MaxRate does not match")
}
if !decodedMsg.Commission.MaxChangeRate.Equal(msgCreateValidator.Commission.MaxChangeRate) {
t.Error("MaxChangeRate does not match")
}
if !reflect.DeepEqual(decodedMsg.Description, msgCreateValidator.Description) {
t.Error("Description does not match")
}
if decodedMsg.MinSelfDelegation.Cmp(msgCreateValidator.MinSelfDelegation) != 0 {
t.Error("MinSelfDelegation does not match")
}
if decodedMsg.StakingAddress.Hex() != msgCreateValidator.StakingAddress.Hex() {
t.Error("StakingAddress does not match")
}
if shard.CompareBlsPublicKey(decodedMsg.ValidatingPubKey, msgCreateValidator.ValidatingPubKey) != 0 {
t.Error("ValidatingPubKey does not match")
}
if decodedMsg.Amount.Cmp(msgCreateValidator.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgEditValidatorRLP(t *testing.T) {
commissionRate := NewDecWithPrec(1, 2) // 10%
blsPublickey := shard.BlsPublicKey{}
blsPublickey.FromLibBLSPublicKey(blsPubKey)
msgEditValidator := NewMsgEditValidator(Description{
Name: "validator 1",
Identity: "1",
Website: "harmony.one",
SecurityContact: "11.111.1111",
Details: "the best validator ever",
}, validatorAddress, commissionRate, minSelfDelegation)
rlpBytes, err := rlp.EncodeToBytes(msgEditValidator)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgEditValidator{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if !reflect.DeepEqual(decodedMsg.Description, msgEditValidator.Description) {
t.Error("Description does not match")
}
if decodedMsg.StakingAddress.Hex() != msgEditValidator.StakingAddress.Hex() {
t.Error("StakingAddress does not match")
}
if !decodedMsg.CommissionRate.Equal(msgEditValidator.CommissionRate) {
t.Error("Commission rate does not match")
}
if decodedMsg.MinSelfDelegation.Cmp(msgEditValidator.MinSelfDelegation) != 0 {
t.Error("MinSelfDelegation does not match")
}
}
func TestMsgDelegateRLP(t *testing.T) {
msgDelegate := NewMsgDelegate(delegatorAddress, validatorAddress, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgDelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgDelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if decodedMsg.DelegatorAddress.Hex() != msgDelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
if decodedMsg.ValidatorAddress.Hex() != msgDelegate.ValidatorAddress.Hex() {
t.Error("ValidatorAddress does not match")
}
if decodedMsg.Amount.Cmp(msgDelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgRedelegateRLP(t *testing.T) {
msgRedelegate := NewMsgRedelegate(delegatorAddress, validatorAddress, validatorAddress2, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgRedelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgRedelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if decodedMsg.DelegatorAddress.Hex() != msgRedelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
if decodedMsg.ValidatorSrcAddress.Hex() != msgRedelegate.ValidatorSrcAddress.Hex() {
t.Error("ValidatorSrcAddress does not match")
}
if decodedMsg.ValidatorDstAddress.Hex() != msgRedelegate.ValidatorDstAddress.Hex() {
t.Error("ValidatorDstAddress does not match")
}
if decodedMsg.Amount.Cmp(msgRedelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgUndelegateRLP(t *testing.T) {
msgUndelegate := NewMsgUndelegate(delegatorAddress, validatorAddress, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgUndelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgUndelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
// var (
// minSelfDelegation = big.NewInt(1000)
// stakeAmount = big.NewInt(2000)
// delegateAmount = big.NewInt(500)
// validatorAddress = common.Address(common.MustBech32ToAddress("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy"))
// validatorAddress2 = common.Address(common.MustBech32ToAddress("one1d2rngmem4x2c6zxsjjz29dlah0jzkr0k2n88wc"))
// delegatorAddress = common.Address(common.MustBech32ToAddress("one16qsd5ant9v94jrs89mruzx62h7ekcfxmduh2rx"))
// blsPubKey = bls.RandPrivateKey().GetPublicKey()
// )
// func TestMsgCreateValidatorRLP(t *testing.T) {
// commissionRate := NewDecWithPrec(1, 2) // 10%
// maxRate := NewDecWithPrec(2, 2) // 20%
// maxChangeRate := NewDecWithPrec(1, 3) // 1%
// blsPublickey := shard.BlsPublicKey{}
// blsPublickey.FromLibBLSPublicKey(blsPubKey)
// msgCreateValidator := NewMsgCreateValidator(Description{
// Name: "validator 1",
// Identity: "1",
// Website: "harmony.one",
// SecurityContact: "11.111.1111",
// Details: "the best validator ever",
// }, CommissionRates{
// Rate: commissionRate,
// MaxRate: maxRate,
// MaxChangeRate: maxChangeRate,
// }, minSelfDelegation, validatorAddress, blsPublickey, stakeAmount)
// rlpBytes, err := rlp.EncodeToBytes(msgCreateValidator)
// if err != nil {
// t.Error("failed to rlp encode 'create validator' message")
// }
// decodedMsg := &MsgCreateValidator{}
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
// if err != nil {
// t.Error("failed to rlp decode 'create validator' message")
// }
// if !decodedMsg.Commission.Rate.Equal(msgCreateValidator.Commission.Rate) {
// t.Error("Commission rate does not match")
// }
// if !decodedMsg.Commission.MaxRate.Equal(msgCreateValidator.Commission.MaxRate) {
// t.Error("MaxRate does not match")
// }
// if !decodedMsg.Commission.MaxChangeRate.Equal(msgCreateValidator.Commission.MaxChangeRate) {
// t.Error("MaxChangeRate does not match")
// }
// if !reflect.DeepEqual(decodedMsg.Description, msgCreateValidator.Description) {
// t.Error("Description does not match")
// }
// if decodedMsg.MinSelfDelegation.Cmp(msgCreateValidator.MinSelfDelegation) != 0 {
// t.Error("MinSelfDelegation does not match")
// }
// if decodedMsg.StakingAddress.String() != msgCreateValidator.StakingAddress.String() {
// t.Error("StakingAddress does not match")
// }
// if shard.CompareBlsPublicKey(decodedMsg.ValidatingPubKey, msgCreateValidator.ValidatingPubKey) != 0 {
// t.Error("ValidatingPubKey does not match")
// }
// if decodedMsg.Amount.Cmp(msgCreateValidator.Amount) != 0 {
// t.Error("Amount does not match")
// }
// }
// func TestMsgEditValidatorRLP(t *testing.T) {
// commissionRate := NewDecWithPrec(1, 2) // 10%
// blsPublickey := shard.BlsPublicKey{}
// blsPublickey.FromLibBLSPublicKey(blsPubKey)
// msgEditValidator := NewMsgEditValidator(Description{
// Name: "validator 1",
// Identity: "1",
// Website: "harmony.one",
// SecurityContact: "11.111.1111",
// Details: "the best validator ever",
// }, validatorAddress, commissionRate, minSelfDelegation)
// rlpBytes, err := rlp.EncodeToBytes(msgEditValidator)
// if err != nil {
// t.Error("failed to rlp encode 'create validator' message")
// }
// decodedMsg := &MsgEditValidator{}
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
// if err != nil {
// t.Error("failed to rlp decode 'create validator' message")
// }
// if !reflect.DeepEqual(decodedMsg.Description, msgEditValidator.Description) {
// t.Error("Description does not match")
// }
// if decodedMsg.StakingAddress.String() != msgEditValidator.StakingAddress.String() {
// t.Error("StakingAddress does not match")
// }
// if !decodedMsg.CommissionRate.Equal(msgEditValidator.CommissionRate) {
// t.Error("Commission rate does not match")
// }
// if decodedMsg.MinSelfDelegation.Cmp(msgEditValidator.MinSelfDelegation) != 0 {
// t.Error("MinSelfDelegation does not match")
// }
// }
// func TestMsgDelegateRLP(t *testing.T) {
// msgDelegate := NewMsgDelegate(delegatorAddress, validatorAddress, delegateAmount)
// rlpBytes, err := rlp.EncodeToBytes(msgDelegate)
// if err != nil {
// t.Error("failed to rlp encode 'create validator' message")
// }
// decodedMsg := &MsgDelegate{}
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
// if err != nil {
// t.Error("failed to rlp decode 'create validator' message")
// }
// if decodedMsg.DelegatorAddress.String() != msgDelegate.DelegatorAddress.String() {
// t.Error("DelegatorAddress does not match")
// }
// if decodedMsg.ValidatorAddress.String() != msgDelegate.ValidatorAddress.String() {
// t.Error("ValidatorAddress does not match")
// }
// if decodedMsg.Amount.Cmp(msgDelegate.Amount) != 0 {
// t.Error("Amount does not match")
// }
// }
// func TestMsgRedelegateRLP(t *testing.T) {
// msgRedelegate := NewMsgRedelegate(delegatorAddress, validatorAddress, validatorAddress2, delegateAmount)
// rlpBytes, err := rlp.EncodeToBytes(msgRedelegate)
// if err != nil {
// t.Error("failed to rlp encode 'create validator' message")
// }
// decodedMsg := &MsgRedelegate{}
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
// if err != nil {
// t.Error("failed to rlp decode 'create validator' message")
// }
// if decodedMsg.DelegatorAddress.String() != msgRedelegate.DelegatorAddress.String() {
// t.Error("DelegatorAddress does not match")
// }
// if decodedMsg.ValidatorSrcAddress.String() != msgRedelegate.ValidatorSrcAddress.String() {
// t.Error("ValidatorSrcAddress does not match")
// }
// if decodedMsg.ValidatorDstAddress.String() != msgRedelegate.ValidatorDstAddress.String() {
// t.Error("ValidatorDstAddress does not match")
// }
// if decodedMsg.Amount.Cmp(msgRedelegate.Amount) != 0 {
// t.Error("Amount does not match")
// }
// }
// func TestMsgUndelegateRLP(t *testing.T) {
// msgUndelegate := NewMsgUndelegate(delegatorAddress, validatorAddress, delegateAmount)
// rlpBytes, err := rlp.EncodeToBytes(msgUndelegate)
// if err != nil {
// t.Error("failed to rlp encode 'create validator' message")
// }
// decodedMsg := &MsgUndelegate{}
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
// if err != nil {
// t.Error("failed to rlp decode 'create validator' message")
// }
if decodedMsg.DelegatorAddress.Hex() != msgUndelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
// if decodedMsg.DelegatorAddress.String() != msgUndelegate.DelegatorAddress.String() {
// t.Error("DelegatorAddress does not match")
// }
if decodedMsg.ValidatorAddress.Hex() != msgUndelegate.ValidatorAddress.Hex() {
t.Error("ValidatorAddress does not match")
}
// if decodedMsg.ValidatorAddress.String() != msgUndelegate.ValidatorAddress.String() {
// t.Error("ValidatorAddress does not match")
// }
if decodedMsg.Amount.Cmp(msgUndelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
// if decodedMsg.Amount.Cmp(msgUndelegate.Amount) != 0 {
// t.Error("Amount does not match")
// }
// }

@ -0,0 +1,199 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// 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 types
import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/crypto/hash"
)
// sigCache is used to cache the derived sender and contains
// the signer used to derive it.
type sigCache struct {
signer Signer
from common.Address
}
// Sign signs the stake using the given signer and private key
func Sign(tx *StakingTransaction, s Signer, prv *ecdsa.PrivateKey) (*StakingTransaction, error) {
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], prv)
if err != nil {
return nil, err
}
return tx.WithSignature(s, sig)
}
// Sender returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect
// signature.
//
// Sender may cache the address, allowing it to be used regardless of
// signing method. The cache is invalidated if the cached signer does
// not match the signer used in the current call.
func Sender(signer Signer, tx *StakingTransaction) (common.Address, error) {
if sc := tx.from.Load(); sc != nil {
sigCache := sc.(sigCache)
// If the signer used to derive from in a previous
// call is not the same as used current, invalidate
// the cache.
if sigCache.signer.Equal(signer) {
return sigCache.from, nil
}
}
addr, err := signer.Sender(tx)
if err != nil {
return common.Address{}, err
}
tx.from.Store(sigCache{signer: signer, from: addr})
return addr, nil
}
// Signer encapsulates transaction signature handling. Note that this interface is not a
// stable API and may change at any time to accommodate new protocol rules.
type Signer interface {
// Sender returns the sender address of the transaction.
Sender(tx *StakingTransaction) (common.Address, error)
// SignatureValues returns the raw R, S, V values corresponding to the
// given signature.
SignatureValues(tx *StakingTransaction, sig []byte) (r, s, v *big.Int, err error)
// Hash returns the hash to be signed.
Hash(tx *StakingTransaction) common.Hash
// Equal returns true if the given signer is the same as the receiver.
Equal(s Signer) bool
}
// EIP155Signer implements Signer using the EIP155 rules.
type EIP155Signer struct {
chainID, chainIDMul *big.Int
}
// NewEIP155Signer creates a EIP155Signer given chainID.
func NewEIP155Signer(chainID *big.Int) EIP155Signer {
if chainID == nil {
chainID = new(big.Int)
}
return EIP155Signer{
chainID: chainID,
chainIDMul: new(big.Int).Mul(chainID, big.NewInt(2)),
}
}
// Equal checks if the given EIP155Signer is equal to another Signer.
func (s EIP155Signer) Equal(s2 Signer) bool {
eip155, ok := s2.(EIP155Signer)
return ok && eip155.chainID.Cmp(s.chainID) == 0
}
var big8 = big.NewInt(8)
// Sender returns the sender address of the given signer.
func (s EIP155Signer) Sender(tx *StakingTransaction) (common.Address, error) {
if tx.ChainID().Cmp(s.chainID) != 0 {
return common.Address{}, core.ErrInvalidChainID
}
V := new(big.Int).Sub(tx.data.V, s.chainIDMul)
V.Sub(V, big8)
return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
}
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) SignatureValues(
tx *StakingTransaction, sig []byte,
) (R, S, V *big.Int, err error) {
sigValues := func(tx *StakingTransaction, sig []byte) (r, s, v *big.Int, err error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v, nil
}
R, S, V, err = sigValues(tx, sig)
if err != nil {
return nil, nil, nil, err
}
if s.chainID.Sign() != 0 {
V = big.NewInt(int64(sig[64] + 35))
V.Add(V, s.chainIDMul)
}
return R, S, V, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s EIP155Signer) Hash(tx *StakingTransaction) common.Hash {
return hash.FromRLP([]interface{}{
tx.data.Directive,
tx.data.StakeMsg,
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
s.chainID, uint(0), uint(0),
})
}
func recoverPlain(
sighash common.Hash, R, S, Vb *big.Int, homestead bool,
) (common.Address, error) {
if Vb.BitLen() > 8 {
return common.Address{}, ErrInvalidSig
}
V := byte(Vb.Uint64() - 27)
if !crypto.ValidateSignatureValues(V, R, S, homestead) {
return common.Address{}, ErrInvalidSig
}
// encode the signature in uncompressed format
r, s := R.Bytes(), S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V
// recover the public key from the signature
pub, err := crypto.Ecrecover(sighash[:], sig)
if err != nil {
return common.Address{}, err
}
if len(pub) == 0 || pub[0] != 4 {
return common.Address{}, errors.New("invalid public key")
}
var addr common.Address
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
return addr, nil
}
// deriveChainID derives the chain id from the given v parameter
func deriveChainID(v *big.Int) *big.Int {
if v.BitLen() <= 64 {
v := v.Uint64()
if v == 27 || v == 28 {
return new(big.Int)
}
return new(big.Int).SetUint64((v - 35) / 2)
}
v = new(big.Int).Sub(v, big.NewInt(35))
return v.Div(v, big.NewInt(2))
}

@ -1,39 +0,0 @@
package types
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/hash"
)
// StakingTransaction struct.
type StakingTransaction struct {
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"`
Msg StakingMessage `json:"msg" gencodec:"required"`
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
// This is only used when marshaling to JSON.
hash *common.Hash `json:"hash" rlp:"-"`
}
// StakingTransactions is a Transaction slice type for basic sorting.
type StakingTransactions []*StakingTransaction
// Hash hashes the RLP encoding of tx.
// It uniquely identifies the transaction.
func (tx *StakingTransaction) Hash() common.Hash {
emptyHash := common.Hash{}
if bytes.Compare(tx.hash[:], emptyHash[:]) == 0 {
h := hash.FromRLP(tx)
tx.hash = &h
}
return *tx.hash
}

@ -0,0 +1,110 @@
package types
import (
"errors"
"io"
"math/big"
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/crypto/hash"
)
type txdata struct {
Directive
StakeMsg interface{}
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"`
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
// This is only used when marshaling to JSON.
Hash *common.Hash `json:"hash" rlp:"-"`
}
// StakingTransaction is a record captuing all staking operations
type StakingTransaction struct {
data txdata
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
}
type fulfill func() (Directive, interface{})
// NewStakingTransaction produces a new staking transaction record
func NewStakingTransaction(
nonce, gasLimit uint64, gasPrice *big.Int, f fulfill,
) (*StakingTransaction, error) {
directive, payload := f()
// TODO(Double check that this is legitmate directive)
newStake := &StakingTransaction{data: txdata{
directive,
payload,
nonce,
big.NewInt(0).Set(gasPrice),
gasLimit,
big.NewInt(0),
big.NewInt(0),
big.NewInt(0),
nil,
}}
return newStake, nil
}
var (
// ErrInvalidSig is a bad signature
ErrInvalidSig = errors.New("invalid transaction v, r, s values")
)
// StakingTransactions is a stake slice type for basic sorting.
type StakingTransactions []*StakingTransaction
// Hash hashes the RLP encoding of tx.
// It uniquely identifies the transaction.
func (tx *StakingTransaction) Hash() common.Hash {
if hash := tx.hash.Load(); hash != nil {
return hash.(common.Hash)
}
v := hash.FromRLP(tx)
tx.hash.Store(v)
return v
}
// WithSignature returns a new transaction with the given signature.
func (tx *StakingTransaction) WithSignature(signer Signer, sig []byte) (*StakingTransaction, error) {
r, s, v, err := signer.SignatureValues(tx, sig)
if err != nil {
return nil, err
}
cpy := &StakingTransaction{data: tx.data}
cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
return cpy, nil
}
// ChainID is what chain this staking transaction for
func (tx *StakingTransaction) ChainID() *big.Int {
return deriveChainID(tx.data.V)
}
// EncodeRLP implements rlp.Encoder
func (tx *StakingTransaction) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &tx.data)
}
// DecodeRLP implements rlp.Decoder
func (tx *StakingTransaction) DecodeRLP(s *rlp.Stream) error {
_, size, _ := s.Kind()
err := s.Decode(&tx.data)
if err != nil {
return err
}
if err == nil {
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
}
return err
}

@ -7,19 +7,28 @@ import (
"github.com/harmony-one/harmony/internal/common"
)
// Define validator staking related const
const (
MaxNameLength = 70
MaxIdentityLength = 3000
MaxWebsiteLength = 140
MaxSecurityContactLength = 140
MaxDetailsLength = 280
)
// Validator - data fields for a validator
type Validator struct {
Address common.Address `json:"address" yaml:"address"` // ECDSA address of the validator
ValidatingPubKey bls.PublicKey `json:"validating_pub_key" yaml:"validating_pub_key"` // The BLS public key of the validator for consensus
Description Description `json:"description" yaml:"description"` // description for the validator
Active bool `json:"active" yaml:"active"` // Is the validator active in the validating process or not
Stake big.Int `json:"stake" yaml:"stake"` // The stake put by the validator itself
UnbondingHeight big.Int `json:"unbonding_height" yaml:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
Stake *big.Int `json:"stake" yaml:"stake"` // The stake put by the validator itself
UnbondingHeight *big.Int `json:"unbonding_height" yaml:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
Commission Commission `json:"commission" yaml:"commission"` // commission parameters
MinSelfDelegation big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // validator's self declared minimum self delegation
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // validator's self declared minimum self delegation
}
// Description - description fields for a validator
// Description - some possible IRL connections
type Description struct {
Name string `json:"name" yaml:"name"` // name
Identity string `json:"identity" yaml:"identity"` // optional identity signature (ex. UPort or Keybase)

@ -6,21 +6,18 @@ import (
"log"
"math/big"
types2 "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/core"
core_state "github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/internal/params"
pkgworker "github.com/harmony-one/harmony/node/worker"
staking "github.com/harmony-one/harmony/staking/types"
)
const (
@ -129,7 +126,7 @@ func fundFaucetContract(chain *core.BlockChain) {
amount := 720000
tx, _ := types.SignTx(types.NewTransaction(nonce+uint64(4), StakingAddress, 0, big.NewInt(int64(amount)), params.TxGas, nil, nil), types.HomesteadSigner{}, FaucetPriKey)
txs = append(txs, tx)
err := contractworker.CommitTransactions(txs, types2.StakingTransactions{}, testUserAddress)
err := contractworker.CommitTransactions(txs, staking.StakingTransactions{}, testUserAddress)
if err != nil {
fmt.Println(err)
}
@ -167,7 +164,7 @@ func callFaucetContractToFundAnAddress(chain *core.BlockChain) {
callEnc = append(callEnc, paddedAddress...)
callfaucettx, _ := types.SignTx(types.NewTransaction(nonce+uint64(5), faucetContractAddress, 0, big.NewInt(0), params.TxGasContractCreation*10, nil, callEnc), types.HomesteadSigner{}, FaucetPriKey)
err = contractworker.CommitTransactions(types.Transactions{callfaucettx}, types2.StakingTransactions{}, testUserAddress)
err = contractworker.CommitTransactions(types.Transactions{callfaucettx}, staking.StakingTransactions{}, testUserAddress)
if err != nil {
fmt.Println(err)
}
@ -245,7 +242,7 @@ func playStaking(chain *core.BlockChain) {
tx, _ := types.SignTx(types.NewTransaction(0, stakeContractAddress, 0, big.NewInt(int64(stake)), params.TxGas*5, nil, callEncl), types.HomesteadSigner{}, allRandomUserKey[i])
stakingtxns = append(stakingtxns, tx)
}
err = contractworker.CommitTransactions(stakingtxns, types2.StakingTransactions{}, common.Address{})
err = contractworker.CommitTransactions(stakingtxns, staking.StakingTransactions{}, common.Address{})
if err != nil {
fmt.Println(err)
@ -303,7 +300,7 @@ func playWithdrawStaking(chain *core.BlockChain) {
withdrawstakingtxns = append(withdrawstakingtxns, tx)
}
err = contractworker.CommitTransactions(withdrawstakingtxns, types2.StakingTransactions{}, common.Address{})
err = contractworker.CommitTransactions(withdrawstakingtxns, staking.StakingTransactions{}, common.Address{})
if err != nil {
fmt.Println("error:")
fmt.Println(err)

Loading…
Cancel
Save