Merge remote-tracking branch 'origin/master' into t3

pull/3118/head
Leo Chen 5 years ago
commit edf69ed841
  1. 21
      README.md
  2. 53
      api/proto/node/node.go
  3. 18
      api/service/manager.go
  4. 12
      api/service/networkinfo/service.go
  5. 1
      consensus/consensus.go
  6. 30
      consensus/consensus_service.go
  7. 15
      consensus/consensus_v2.go
  8. 8
      consensus/view_change.go
  9. 16
      core/tx_list.go
  10. 37
      core/tx_pool.go
  11. 39
      hmy/api_backend.go
  12. 2
      internal/hmyapi/apiv1/backend.go
  13. 90
      internal/hmyapi/apiv1/blockchain.go
  14. 54
      internal/hmyapi/apiv1/types.go
  15. 2
      internal/hmyapi/apiv2/backend.go
  16. 90
      internal/hmyapi/apiv2/blockchain.go
  17. 56
      internal/hmyapi/apiv2/types.go
  18. 2
      internal/hmyapi/backend.go
  19. 2
      node/node.go
  20. 2
      scripts/node.sh
  21. 4
      staking/types/validator.go
  22. 1
      test/debug.sh
  23. 19
      test/deploy.sh

@ -38,8 +38,8 @@ $ git reset --hard origin/master
```
$ git fetch
$ git checkout s3
$ git reset --hard origin/s3
$ git checkout t3
$ git reset --hard origin/t3
```
And now run the local blockchain
@ -118,13 +118,20 @@ $ eval $(gimme 1.14.1)
Note that changing the go version might mean that dependencies won't work out right when trying to
run `test/debug.sh` again, get the correct environment again easily by `exec bash`.
## Installation Requirements for directly on your machine
## Installation Requirements for directly on your MacOS X
GMP and OpenSSL
```bash
brew install gmp
brew install openssl
```
## On Linux Box (assuming Amazon Linux 2 or Cent OS)
```bash
sudo yum install glibc-static gmp-devel gmp-static openssl-libs openssl-static gcc-c++
```
## Dev Environment Setup
@ -243,11 +250,9 @@ See [`CONTRIBUTING`](CONTRIBUTING.md) for details.
- EPoS staking mechanism
- Kademlia routing
### Features To Be Implemented
- Leader rotation
### Features Planned after Mainnet
### Features Planned after Mainnet Open Staking
- Resharding
- Integration with WASM
- Fast state synchronization
- Auditable privacy asset using ZK proof

@ -2,10 +2,8 @@ package node
import (
"bytes"
"fmt"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/block"
@ -14,7 +12,6 @@ import (
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/staking/slash"
staking "github.com/harmony-one/harmony/staking/types"
libp2p_peer "github.com/libp2p/go-libp2p-core/peer"
)
// MessageType is to indicate the specific type of message under Node category
@ -31,22 +28,6 @@ const (
Staking
)
// BlockchainSyncMessage is a struct for blockchain sync message.
type BlockchainSyncMessage struct {
BlockHeight int
BlockHashes []common.Hash
}
// BlockchainSyncMessageType represents BlockchainSyncMessageType type.
type BlockchainSyncMessageType int
// Constant of blockchain sync-up message subtype
const (
Done BlockchainSyncMessageType = iota
GetLastBlockHashes
GetBlock
)
// TransactionMessageType representa the types of messages used for Node/Transaction
type TransactionMessageType int
@ -56,40 +37,6 @@ const (
Unlock
)
// RoleType defines the role of the node
type RoleType int
// Type of roles of a node
const (
ValidatorRole RoleType = iota
ClientRole
)
func (r RoleType) String() string {
switch r {
case ValidatorRole:
return "Validator"
case ClientRole:
return "Client"
}
return "Unknown"
}
// Info refers to Peer struct in p2p/peer.go
// this is basically a simplified version of Peer
// for network transportation
type Info struct {
IP string
Port string
PubKey []byte
Role RoleType
PeerID libp2p_peer.ID // Peerstore ID
}
func (info Info) String() string {
return fmt.Sprintf("Info:%v/%v=>%v", info.IP, info.Port, info.PeerID.Pretty())
}
// BlockMessageType represents the type of messages used for Node/Block
type BlockMessageType int

@ -1,8 +1,6 @@
package service
import (
"time"
"github.com/ethereum/go-ethereum/rpc"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
"github.com/harmony-one/harmony/internal/utils"
@ -28,7 +26,6 @@ const (
Consensus
BlockProposal
NetworkInfo
PeerDiscovery
)
func (t Type) String() string {
@ -43,19 +40,11 @@ func (t Type) String() string {
return "BlockProposal"
case NetworkInfo:
return "NetworkInfo"
case PeerDiscovery:
return "PeerDiscovery"
default:
return "Unknown"
}
}
// Constants for timing.
const (
// WaitForStatusUpdate is the delay time to update new status. Currently set 1 second for development. Should be 30 minutes for production.
WaitForStatusUpdate = time.Minute * 1
)
// Action is type of service action.
type Action struct {
Action ActionType
@ -114,11 +103,6 @@ func (m *Manager) InitServiceMap() {
m.services = make(map[Type]Interface)
}
// SendAction sends action to action channel which is observed by service manager.
func (m *Manager) SendAction(action *Action) {
m.actionChannel <- action
}
// TakeAction is how service manager handles the action.
func (m *Manager) TakeAction(action *Action) {
if m.services == nil {
@ -145,8 +129,6 @@ func (m *Manager) StartServiceManager() chan *Action {
select {
case action := <-ch:
m.TakeAction(action)
case <-time.After(WaitForStatusUpdate):
utils.Logger().Info().Msg("Waiting for new action")
}
}
}()

@ -196,13 +196,22 @@ func (s *Service) DoService() {
case <-s.stopChan:
return
case <-tick.C:
var g sync.WaitGroup
g.Add(2) // 2 Advertise call
go func() {
defer g.Done()
libp2pdis.Advertise(ctx, s.discovery, string(s.Rendezvous))
}()
go func() {
defer g.Done()
// 0 is beacon chain FIXME: use a constant
libp2pdis.Advertise(ctx, s.discovery, string(nodeconfig.NewClientGroupIDByShardID(0)))
}()
g.Wait()
utils.Logger().Info().
Str("Rendezvous", string(s.Rendezvous)).
Msg("Successfully announced!")
default:
case <-time.After(findPeerInterval):
var err error
s.peerInfo, err = s.discovery.FindPeers(
ctx, string(s.Rendezvous), coredis.Limit(discoveryLimit),
@ -213,7 +222,6 @@ func (s *Service) DoService() {
}
s.findPeers(ctx)
time.Sleep(findPeerInterval)
}
}
}

@ -90,6 +90,7 @@ type Consensus struct {
// whether to ignore viewID check
ignoreViewIDCheck bool
// global consensus mutex
// TODO(optimization): Avoid mutex and use more efficient locking primitives
mutex sync.Mutex
// consensus information update mutex
infoMutex sync.Mutex

@ -15,10 +15,8 @@ import (
"github.com/harmony-one/harmony/internal/chain"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/multibls"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
libp2p_peer "github.com/libp2p/go-libp2p-core/peer"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)
@ -68,19 +66,6 @@ func (consensus *Consensus) signAndMarshalConsensusMessage(message *msg_pb.Messa
return marshaledMessage, nil
}
// GetNodeIDs returns Node IDs of all nodes in the same shard
func (consensus *Consensus) GetNodeIDs() []libp2p_peer.ID {
nodes := []libp2p_peer.ID{consensus.host.GetID()}
consensus.validators.Range(func(k, v interface{}) bool {
if peer, ok := v.(p2p.Peer); ok {
nodes = append(nodes, peer.PeerID)
return true
}
return false
})
return nodes
}
// GetViewID returns the consensus ID
func (consensus *Consensus) GetViewID() uint64 {
return consensus.viewID
@ -135,21 +120,6 @@ func (consensus *Consensus) signConsensusMessage(message *msg_pb.Message,
return nil
}
// GetValidatorPeers returns list of validator peers.
func (consensus *Consensus) GetValidatorPeers() []p2p.Peer {
validatorPeers := []p2p.Peer{}
consensus.validators.Range(func(k, v interface{}) bool {
if peer, ok := v.(p2p.Peer); ok {
validatorPeers = append(validatorPeers, peer)
return true
}
return false
})
return validatorPeers
}
// GetViewIDSigsArray returns the signatures for viewID in viewchange
func (consensus *Consensus) GetViewIDSigsArray(viewID uint64) []*bls.Sign {
sigs := []*bls.Sign{}

@ -257,12 +257,6 @@ func (consensus *Consensus) tryCatchup() {
continue
}
if consensus.BlockVerifier == nil {
// do nothing
} else if err := consensus.BlockVerifier(tmpBlock); err != nil {
consensus.getLogger().Info().Msg("[TryCatchup] block verification failed")
continue
}
committedMsg = msgs[i]
block = tmpBlock
break
@ -334,7 +328,7 @@ func (consensus *Consensus) Start(
blockChannel chan *types.Block, stopChan, stoppedChan, startChannel chan struct{},
) {
go func() {
toStart := false
toStart := make(chan struct{}, 1)
isInitialLeader := consensus.IsLeader()
if isInitialLeader {
consensus.getLogger().Info().Time("time", time.Now()).Msg("[ConsensusMainLoop] Waiting for consensus start")
@ -342,7 +336,7 @@ func (consensus *Consensus) Start(
// this signal is consumed by node object to create a new block and in turn trigger a new consensus on it
go func() {
<-startChannel
toStart = true
toStart <- struct{}{}
consensus.getLogger().Info().Time("time", time.Now()).Msg("[ConsensusMainLoop] Send ReadySignal")
consensus.ReadySignal <- struct{}{}
}()
@ -360,11 +354,14 @@ func (consensus *Consensus) Start(
vdfInProgress := false
// Set up next block due time.
consensus.NextBlockDue = time.Now().Add(consensus.BlockPeriod)
start := false
for {
select {
case <-toStart:
start = true
case <-ticker.C:
consensus.getLogger().Debug().Msg("[ConsensusMainLoop] Ticker")
if !toStart && isInitialLeader {
if !start && isInitialLeader {
continue
}
for k, v := range consensus.consensusTimeout {

@ -543,6 +543,10 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
return
}
hasBlock = true
if consensus.BlockVerifier(preparedBlock); err != nil {
consensus.getLogger().Error().Err(err).Msg("[onNewView] Prepared block verification failed")
return
}
}
if m2Mask == nil || m2Mask.Bitmap == nil ||
@ -605,10 +609,6 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
// NewView message is verified, change state to normal consensus
if hasBlock {
// Construct and send the commit message
if consensus.BlockVerifier(preparedBlock); err != nil {
consensus.getLogger().Error().Err(err).Msg("[onNewView] Prepared block verification failed")
return
}
commitPayload := signature.ConstructCommitPayload(consensus.ChainReader,
preparedBlock.Epoch(), preparedBlock.Hash(), preparedBlock.NumberU64(), preparedBlock.Header().ViewID().Uint64())
groupID := []nodeconfig.GroupID{

@ -283,7 +283,7 @@ func (l *txList) Forward(threshold uint64) types.PoolTransactions {
return l.txs.Forward(threshold)
}
// Filter removes all transactions from the list with a cost or gas limit higher
// FilterCost removes all transactions from the list with a cost or gas limit higher
// than the provided thresholds. Every removed transaction is returned for any
// post-removal maintenance. Strict-mode invalidated transactions are also
// returned.
@ -292,7 +292,7 @@ func (l *txList) Forward(threshold uint64) types.PoolTransactions {
// a point in calculating all the costs or if the balance covers all. If the threshold
// is lower than the costgas cap, the caps will be reset to a new high after removing
// the newly invalidated transactions.
func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.PoolTransactions, types.PoolTransactions) {
func (l *txList) FilterCost(costLimit *big.Int, gasLimit uint64) (types.PoolTransactions, types.PoolTransactions) {
// If all transactions are below the threshold, short circuit
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
return nil, nil
@ -300,18 +300,26 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.PoolTransact
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
l.gascap = gasLimit
// Filter out all the transactions above the account's funds
removed := l.txs.Filter(func(tx types.PoolTransaction) bool {
return l.Filter(func(tx types.PoolTransaction) bool {
cost, err := tx.Cost()
if err != nil {
return true // failure should lead to removal of the tx
}
return cost.Cmp(costLimit) > 0 || tx.Gas() > gasLimit
})
}
// Filter iterates over the list of transactions and removes all of them for which
// the specified function evaluates to true. Moreover, it returns all transactions
// that were invalidated from the filter
func (l *txList) Filter(
filter func(types.PoolTransaction) bool,
) (types.PoolTransactions, types.PoolTransactions) {
// If the list was strict, filter anything above the lowest nonce
var invalids types.PoolTransactions
// Filter out all the transactions above the account's funds
removed := l.txs.Filter(filter)
if l.strict && len(removed) > 0 {
lowest := uint64(math.MaxUint64)
for _, tx := range removed {

@ -616,7 +616,7 @@ func (pool *TxPool) Content() (map[common.Address]types.PoolTransactions, map[co
return pending, queued
}
// Pending retrieves all currently processable transactions, grouped by origin
// Pending retrieves all currently executable transactions, grouped by origin
// account and sorted by nonce. The returned transaction set is a copy and can be
// freely modified by calling code.
func (pool *TxPool) Pending() (map[common.Address]types.PoolTransactions, error) {
@ -630,6 +630,20 @@ func (pool *TxPool) Pending() (map[common.Address]types.PoolTransactions, error)
return pending, nil
}
// Queued retrieves all currently non-executable transactions, grouped by origin
// account and sorted by nonce. The returned transaction set is a copy and can be
// freely modified by calling code.
func (pool *TxPool) Queued() (map[common.Address]types.PoolTransactions, error) {
pool.mu.Lock()
defer pool.mu.Unlock()
queued := make(map[common.Address]types.PoolTransactions)
for addr, list := range pool.queue {
queued[addr] = list.Flatten()
}
return queued, nil
}
// Locals retrieves the accounts currently considered local by the pool.
func (pool *TxPool) Locals() []common.Address {
pool.mu.Lock()
@ -1262,7 +1276,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
}
// Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas)
drops, _ := list.FilterCost(pool.currentState.GetBalance(addr), pool.currentMaxGas)
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
@ -1435,14 +1449,25 @@ func (pool *TxPool) demoteUnexecutables() {
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas)
drops, invalids := list.FilterCost(pool.currentState.GetBalance(addr), pool.currentMaxGas)
// Drop all staking transactions that are now invalid, queue any invalids back for later
stakingDrops, stakingInvalids := list.Filter(func(tx types.PoolTransaction) bool {
if _, ok := tx.(*staking.StakingTransaction); !ok {
// Do not remove anything other than staking transactions
return false
}
err := pool.validateTx(tx, false)
return err != nil
})
drops = append(drops, stakingDrops...)
invalids = append(invalids, stakingInvalids...)
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
pool.priced.Removed()
pendingNofundsCounter.Inc(1)
pool.txErrorSink.Add(tx, fmt.Errorf("removed unpayable pending transaction"))
logger.Warn().Str("hash", hash.Hex()).Msg("Removed unpayable pending transaction")
pool.txErrorSink.Add(tx, fmt.Errorf("removed unexecutable pending transaction"))
logger.Warn().Str("hash", hash.Hex()).Msg("Removed unexecutable pending transaction")
}
for _, tx := range invalids {
hash := tx.Hash()
@ -1451,7 +1476,7 @@ func (pool *TxPool) demoteUnexecutables() {
pool.txErrorSink.Add(tx, err)
}
}
// If there's a gap in front, alert (should never happen) and postpone all transactions
// If there's a gap in front, alert (should never happen)
if list.Len() > 0 && list.txs.Get(nonce) == nil {
for _, tx := range list.Cap(0) {
hash := tx.Hash()

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum"
@ -20,6 +21,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
@ -243,10 +245,17 @@ func (b *APIBackend) GetPoolTransactions() (types.PoolTransactions, error) {
if err != nil {
return nil, err
}
queued, err := b.hmy.txPool.Queued()
if err != nil {
return nil, err
}
var txs types.PoolTransactions
for _, batch := range pending {
txs = append(txs, batch...)
}
for _, batch := range queued {
txs = append(txs, batch...)
}
return txs, nil
}
@ -848,3 +857,33 @@ func (b *APIBackend) GetNodeMetadata() commonRPC.NodeMetadata {
c,
}
}
// GetBlockSigners ..
func (b *APIBackend) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *internal_bls.Mask, error) {
block, err := b.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, nil, err
}
blockWithSigners, err := b.BlockByNumber(ctx, blockNr+1)
if err != nil {
return nil, nil, err
}
committee, err := b.GetValidators(block.Epoch())
if err != nil {
return nil, nil, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return nil, nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return nil, nil, err
}
return committee.Slots, mask, nil
}

@ -14,6 +14,7 @@ import (
"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/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
@ -91,4 +92,5 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}

@ -18,7 +18,6 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
@ -183,9 +182,6 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.Bloc
// GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
if err := s.isBeaconShard(); err != nil {
return nil, err
}
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
@ -217,6 +213,20 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
return result, nil
}
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
}
validators := make([]string, len(committee.Slots))
for i, v := range committee.Slots {
validators[i] = v.BLSPublicKey.Hex()
}
return validators, nil
}
// IsLastBlock checks if block is last epoch block.
func (s *PublicBlockChainAPI) IsLastBlock(blockNum uint64) (bool, error) {
if err := s.isBeaconShard(); err != nil {
@ -241,44 +251,46 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.B
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
block, err := s.b.BlockByNumber(ctx, blockNr)
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return nil, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
signers := []string{}
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return nil, err
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
signers = append(signers, oneAddress)
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return nil, err
return signers, nil
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
// GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr rpc.BlockNumber) ([]string, error) {
if uint64(blockNr) == 0 {
return []string{}, nil
}
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
result := []string{}
for _, validator := range committee.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return nil, err
}
signers := []string{}
for _, validator := range slots {
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
result = append(result, oneAddress)
signers = append(signers, validator.BLSPublicKey.Hex())
}
}
return result, nil
return signers, nil
}
// IsBlockSigner returns true if validator with address signed blockNr block.
@ -289,32 +301,11 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr rpc.Blo
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return false, err
}
block, err := s.b.BlockByNumber(ctx, blockNr)
if err != nil {
return false, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr)
if err != nil {
return false, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return false, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return false, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return false, err
}
for _, validator := range committee.Slots {
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return false, err
@ -683,17 +674,16 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start
}
}
validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
}
for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block)
if err != nil {
return nil, err
if err == nil {
validators = append(validators, information)
}
validators[i-start] = information
}
return validators, nil
}

@ -6,7 +6,7 @@ import (
"strings"
"time"
types2 "github.com/harmony-one/harmony/staking/types"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -208,7 +208,7 @@ func newRPCTransaction(
// newRPCStakingTransaction returns a staking transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Hash,
func newRPCStakingTransaction(tx *staking.StakingTransaction, blockHash common.Hash,
blockNumber uint64, timestamp uint64, index uint64,
) *RPCStakingTransaction {
from, err := tx.SenderAddress()
@ -217,13 +217,15 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
}
v, r, s := tx.RawSignatureValues()
stakingTxType := tx.StakingType()
message := tx.StakingMessage()
fields := map[string]interface{}{}
switch stakingTxType {
case types2.DirectiveCreateValidator:
msg, ok := message.(types2.CreateValidator)
switch tx.StakingType() {
case staking.DirectiveCreateValidator:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveCreateValidator)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.CreateValidator)
if !ok {
return nil
}
@ -246,8 +248,12 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
"details": msg.Description.Details,
"slotPubKeys": msg.SlotPubKeys,
}
case types2.DirectiveEditValidator:
msg, ok := message.(types2.EditValidator)
case staking.DirectiveEditValidator:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveEditValidator)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.EditValidator)
if !ok {
return nil
}
@ -273,8 +279,12 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
"slotPubKeyToAdd": msg.SlotKeyToAdd,
"slotPubKeyToRemove": msg.SlotKeyToRemove,
}
case types2.DirectiveCollectRewards:
msg, ok := message.(types2.CollectRewards)
case staking.DirectiveCollectRewards:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveCollectRewards)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.CollectRewards)
if !ok {
return nil
}
@ -285,8 +295,12 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
fields = map[string]interface{}{
"delegatorAddress": delegatorAddress,
}
case types2.DirectiveDelegate:
msg, ok := message.(types2.Delegate)
case staking.DirectiveDelegate:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveDelegate)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.Delegate)
if !ok {
return nil
}
@ -303,8 +317,12 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
"validatorAddress": validatorAddress,
"amount": (*hexutil.Big)(msg.Amount),
}
case types2.DirectiveUndelegate:
msg, ok := message.(types2.Undelegate)
case staking.DirectiveUndelegate:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveUndelegate)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.Undelegate)
if !ok {
return nil
}
@ -332,7 +350,7 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
V: (*hexutil.Big)(v),
R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s),
Type: stakingTxType.String(),
Type: tx.StakingType().String(),
Msg: fields,
}
if blockHash != (common.Hash{}) {
@ -423,11 +441,11 @@ func RPCMarshalBlock(b *types.Block, blockArgs BlockArgs) (map[string]interface{
fields["transactions"] = transactions
if blockArgs.InclStaking {
formatStakingTx := func(tx *types2.StakingTransaction) (interface{}, error) {
formatStakingTx := func(tx *staking.StakingTransaction) (interface{}, error) {
return tx.Hash(), nil
}
if blockArgs.FullTx {
formatStakingTx = func(tx *types2.StakingTransaction) (interface{}, error) {
formatStakingTx = func(tx *staking.StakingTransaction) (interface{}, error) {
return newRPCStakingTransactionFromBlockHash(b, tx.Hash()), nil
}
}

@ -14,6 +14,7 @@ import (
"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/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
@ -87,4 +88,5 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}

@ -17,7 +17,6 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
@ -144,9 +143,6 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEn
// GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
if err := s.isBeaconShard(); err != nil {
return nil, err
}
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
@ -179,6 +175,20 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
return result, nil
}
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
}
validators := make([]string, len(committee.Slots))
for i, v := range committee.Slots {
validators[i] = v.BLSPublicKey.Hex()
}
return validators, nil
}
// IsLastBlock checks if block is last epoch block.
func (s *PublicBlockChainAPI) IsLastBlock(blockNum uint64) (bool, error) {
if err := s.isBeaconShard(); err != nil {
@ -203,44 +213,46 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr uint6
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr+1))
signers := []string{}
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return nil, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return nil, err
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
signers = append(signers, oneAddress)
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return nil, err
return signers, nil
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
// GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr uint64) ([]string, error) {
if blockNr == 0 || blockNr >= uint64(s.BlockNumber()) {
return []string{}, nil
}
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err
}
result := []string{}
for _, validator := range committee.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, err
}
signers := []string{}
for _, validator := range slots {
blsPublicKey := new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
result = append(result, oneAddress)
signers = append(signers, validator.BLSPublicKey.Hex())
}
}
return result, nil
return signers, nil
}
// IsBlockSigner returns true if validator with address signed blockNr block.
@ -251,32 +263,11 @@ func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr uint64,
if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return false, err
}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return false, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr+1))
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return false, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return false, err
}
pubkeys := make([]*bls.PublicKey, len(committee.Slots))
for i, validator := range committee.Slots {
pubkeys[i] = new(bls.PublicKey)
validator.BLSPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return false, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return false, err
}
for _, validator := range committee.Slots {
for _, validator := range slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return false, err
@ -629,17 +620,16 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start
}
}
validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
}
for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block)
if err != nil {
return nil, err
if err == nil {
validators = append(validators, information)
}
validators[i-start] = information
}
return validators, nil
}

@ -6,7 +6,7 @@ import (
"strings"
"time"
types2 "github.com/harmony-one/harmony/staking/types"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -210,7 +210,7 @@ func newRPCTransaction(
// newRPCStakingTransaction returns a staking transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func newRPCStakingTransaction(
tx *types2.StakingTransaction, blockHash common.Hash,
tx *staking.StakingTransaction, blockHash common.Hash,
blockNumber uint64, timestamp uint64, index uint64,
) *RPCStakingTransaction {
from, err := tx.SenderAddress()
@ -219,13 +219,15 @@ func newRPCStakingTransaction(
}
v, r, s := tx.RawSignatureValues()
stakingTxType := tx.StakingType()
message := tx.StakingMessage()
fields := make(map[string]interface{})
switch stakingTxType {
case types2.DirectiveCreateValidator:
msg, ok := message.(types2.CreateValidator)
switch tx.StakingType() {
case staking.DirectiveCreateValidator:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveCreateValidator)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.CreateValidator)
if !ok {
return nil
}
@ -248,8 +250,12 @@ func newRPCStakingTransaction(
"details": msg.Description.Details,
"slotPubKeys": msg.SlotPubKeys,
}
case types2.DirectiveEditValidator:
msg, ok := message.(types2.EditValidator)
case staking.DirectiveEditValidator:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveEditValidator)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.EditValidator)
if !ok {
return nil
}
@ -275,8 +281,12 @@ func newRPCStakingTransaction(
"slotPubKeyToAdd": msg.SlotKeyToAdd,
"slotPubKeyToRemove": msg.SlotKeyToRemove,
}
case types2.DirectiveCollectRewards:
msg, ok := message.(types2.CollectRewards)
case staking.DirectiveCollectRewards:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveCollectRewards)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.CollectRewards)
if !ok {
return nil
}
@ -287,8 +297,12 @@ func newRPCStakingTransaction(
fields = map[string]interface{}{
"delegatorAddress": delegatorAddress,
}
case types2.DirectiveDelegate:
msg, ok := message.(types2.Delegate)
case staking.DirectiveDelegate:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveDelegate)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.Delegate)
if !ok {
return nil
}
@ -305,8 +319,12 @@ func newRPCStakingTransaction(
"validatorAddress": validatorAddress,
"amount": msg.Amount,
}
case types2.DirectiveUndelegate:
msg, ok := message.(types2.Undelegate)
case staking.DirectiveUndelegate:
rawMsg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveUndelegate)
if err != nil {
return nil
}
msg, ok := rawMsg.(*staking.Undelegate)
if !ok {
return nil
}
@ -334,12 +352,12 @@ func newRPCStakingTransaction(
V: (*hexutil.Big)(v),
R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s),
Type: stakingTxType.String(),
Type: tx.StakingType().String(),
Msg: fields,
}
if blockHash != (common.Hash{}) {
result.BlockHash = blockHash
result.BlockNumber = (*big.Int)(new(big.Int).SetUint64(blockNumber))
result.BlockNumber = new(big.Int).SetUint64(blockNumber)
result.TransactionIndex = index
}
@ -425,11 +443,11 @@ func RPCMarshalBlock(b *types.Block, blockArgs BlockArgs) (map[string]interface{
fields["transactions"] = transactions
if blockArgs.InclStaking {
formatStakingTx := func(tx *types2.StakingTransaction) (interface{}, error) {
formatStakingTx := func(tx *staking.StakingTransaction) (interface{}, error) {
return tx.Hash(), nil
}
if blockArgs.FullTx {
formatStakingTx = func(tx *types2.StakingTransaction) (interface{}, error) {
formatStakingTx = func(tx *staking.StakingTransaction) (interface{}, error) {
return newRPCStakingTransactionFromBlockHash(b, tx.Hash()), nil
}
}

@ -14,6 +14,7 @@ import (
"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/bls"
"github.com/harmony-one/harmony/internal/hmyapi/apiv1"
"github.com/harmony-one/harmony/internal/hmyapi/apiv2"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
@ -81,6 +82,7 @@ type Backend interface {
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
}
// GetAPIs returns all the APIs.

@ -138,8 +138,6 @@ type Node struct {
ContractDeployerKey *ecdsa.PrivateKey
ContractDeployerCurrentNonce uint64 // The nonce of the deployer contract at current block
ContractAddresses []common.Address
// Duplicated Ping Message Received
duplicatedPing sync.Map
// Channel to notify consensus service to really start consensus
startConsensus chan struct{}
// node configuration, including group ID, shard ID, etc

@ -530,7 +530,7 @@ any_new_binaries() {
fi
fi
curl -sSf http://${BUCKET}.s3.amazonaws.com/${FOLDER}/md5sum.txt -o "${outdir}/md5sum.txt.new" || return $?
if diff $outdir/md5sum.txt.new md5sum.txt
if diff "${outdir}/md5sum.txt.new" "${outdir}/md5sum.txt"
then
rm "${outdir}/md5sum.txt.new"
else

@ -62,7 +62,7 @@ var (
errDuplicateSlotKeys = errors.New("slot keys can not have duplicates")
// ErrExcessiveBLSKeys ..
ErrExcessiveBLSKeys = errors.New("more slot keys provided than allowed")
errCannotChangeBannedTaint = errors.New("cannot change validator banned status")
errCannotChangeBannedTrait = errors.New("cannot change validator banned status")
)
// ValidatorSnapshotReader ..
@ -645,7 +645,7 @@ func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator, epoch
switch validator.Status {
case effective.Banned:
return errCannotChangeBannedTaint
return errCannotChangeBannedTrait
default:
switch edit.EPOSStatus {
case effective.Active, effective.Inactive:

@ -1,3 +1,4 @@
./test/kill_node.sh
rm -rf tmp_log*
rm *.rlp
./test/deploy.sh -D 60000 ./test/configs/local-resharding.txt

@ -15,6 +15,7 @@ USER=$(whoami)
set -eo pipefail
export GO111MODULE=on
OS=$(uname -s)
mkdir -p .hmy
if [ -f ".hmy/blspass.txt" ]
@ -77,6 +78,7 @@ USAGE: $ME [OPTIONS] config_file_name [extra args to node]
-n dryrun mode (default: $DRYRUN)
-N network network type (default: $NETWORK)
-B don't build the binary
-v verbosity in log (default: $VERBOSE)
This script will build all the binaries and start harmony and based on the configuration file.
@ -95,6 +97,7 @@ SHARDS=2
DRYRUN=
SYNC=true
NETWORK=localnet
VERBOSE=false
while getopts "hD:m:s:nBN:" option; do
case $option in
@ -105,6 +108,7 @@ while getopts "hD:m:s:nBN:" option; do
n) DRYRUN=echo ;;
B) NOBUILD=true ;;
N) NETWORK=$OPTARG ;;
v) VERBOSE=true ;;
esac
done
@ -126,7 +130,13 @@ cleanup
# Also it's recommended to use `go build` for testing the whole exe.
if [ "${NOBUILD}" != "true" ]; then
pushd $ROOT
if [ "$OS" = "Darwin" ]; then
# MacOS doesn't support static build
scripts/go_executable_build.sh -S
else
# Static build on Linux platform
scripts/go_executable_build.sh -s
fi
popd
fi
@ -145,7 +155,14 @@ echo "bootnode launched." + " $BN_MA"
unset -v base_args
declare -a base_args args
base_args=(-log_folder "${log_folder}" -min_peers "${MIN}" -bootnodes "${BN_MA}" -network_type="$NETWORK" -blspass file:.hmy/blspass.txt -dns=false)
if $VERBOSE; then
verbosity=5
else
verbosity=3
fi
base_args=(-log_folder "${log_folder}" -min_peers "${MIN}" -bootnodes "${BN_MA}" -network_type="$NETWORK" -blspass file:.hmy/blspass.txt -dns=false -verbosity="${verbosity}")
sleep 2
# Start nodes

Loading…
Cancel
Save