migrate bls identity from address to public key

Use shard info for committee pub keys rather than pong message

Make code backward compatible
pull/664/head
Rongjian Lan 6 years ago
parent 41e70f425d
commit 6044b76068
  1. 1
      api/proto/discovery/pingpong.go
  2. 1
      api/service/consensus/service.go
  3. 50
      consensus/consensus.go
  4. 32
      consensus/consensus_leader.go
  5. 6
      consensus/consensus_leader_msg_test.go
  6. 4
      consensus/consensus_test.go
  7. 2
      consensus/consensus_validator.go
  8. 16
      contracts/Lottery.go
  9. 50
      contracts/StakeLockContract.go
  10. 28
      contracts/StakeLockContract.sol
  11. 2
      contracts/gen.sh
  12. 8
      contracts/structs/structs.go
  13. 8
      core/blockchain.go
  14. 30
      core/resharding.go
  15. 74
      core/resharding_test.go
  16. 17
      core/types/shard_state.go
  17. 66
      core/types/shard_state_test.go
  18. 35
      drand/drand.go
  19. 16
      drand/drand_leader.go
  20. 6
      internal/utils/utils.go
  21. 6
      internal/utils/utils_test.go
  22. 26
      node/node.go
  23. 31
      node/node_handler.go
  24. 1
      node/node_newblock.go
  25. 4
      node/service_setup.go
  26. 8
      node/staking.go
  27. 8
      node/staking_test.go

@ -95,7 +95,6 @@ func NewPongMessage(peers []p2p.Peer, pubKeys []*bls.PublicKey, leaderKey *bls.P
}
pong.LeaderPubKey = leaderKey.Serialize()
// utils.GetLogInstance().Info("[NewPongMessage]", "keys", len(pong.PubKeys), "peers", len(pong.Peers), "leaderPubKey", utils.GetAddressHex(leaderKey))
return pong
}

@ -24,6 +24,7 @@ func New(blockChannel chan *types.Block, consensus *consensus.Consensus, startCh
// StartService starts consensus service.
func (s *Service) StartService() {
utils.GetLogInstance().Info("Starting consensus service.")
s.stopChan = make(chan struct{})
s.stoppedChan = make(chan struct{})
s.consensus.WaitForNewBlock(s.blockChannel, s.stopChan, s.stoppedChan, s.startChan)

@ -33,8 +33,8 @@ type Consensus struct {
state State
// Commits collected from validators.
prepareSigs map[string]*bls.Sign // key is the validator's address
commitSigs map[string]*bls.Sign // key is the validator's address
prepareSigs map[common.Address]*bls.Sign // key is the validator's address
commitSigs map[common.Address]*bls.Sign // key is the validator's address
aggregatedPrepareSig *bls.Sign
aggregatedCommitSig *bls.Sign
prepareBitmap *bls_cosi.Mask
@ -55,7 +55,8 @@ type Consensus struct {
// Public keys of the committee including leader and validators
PublicKeys []*bls.PublicKey
// The addresses of my committee
CommitteeAddresses map[common.Address]bool
pubKeyLock sync.Mutex
// private/public keys of current node
@ -65,7 +66,7 @@ type Consensus struct {
// Whether I am leader. False means I am validator
IsLeader bool
// Leader or validator address in hex
SelfAddress string
SelfAddress common.Address
// Consensus Id (View Id) - 4 byte
consensusID uint32
// Blockhash - 32 byte
@ -167,12 +168,15 @@ func New(host p2p.Host, ShardID uint32, peers []p2p.Peer, leader p2p.Peer, blsPr
}
consensus.leader = leader
consensus.CommitteeAddresses = map[common.Address]bool{}
for _, peer := range peers {
consensus.validators.Store(utils.GetAddressHex(peer.ConsensusPubKey), peer)
consensus.validators.Store(utils.GetBlsAddress(peer.ConsensusPubKey).Hex(), peer)
consensus.CommitteeAddresses[utils.GetBlsAddress(peer.ConsensusPubKey)] = true
}
consensus.prepareSigs = map[string]*bls.Sign{}
consensus.commitSigs = map[string]*bls.Sign{}
consensus.prepareSigs = map[common.Address]*bls.Sign{}
consensus.commitSigs = map[common.Address]*bls.Sign{}
// Initialize cosign bitmap
allPublicKeys := make([]*bls.PublicKey, 0)
@ -193,7 +197,7 @@ func New(host p2p.Host, ShardID uint32, peers []p2p.Peer, leader p2p.Peer, blsPr
// For now use socket address as ID
// TODO: populate Id derived from address
consensus.SelfAddress = utils.GetAddressHex(selfPeer.ConsensusPubKey)
consensus.SelfAddress = utils.GetBlsAddress(selfPeer.ConsensusPubKey)
if blsPriKey != nil {
consensus.priKey = blsPriKey
@ -276,6 +280,7 @@ func (consensus *Consensus) ToggleConsensusCheck() {
}
// GetPeerByAddress the validator peer based on validator Address.
// TODO: deprecate this, as validators network info shouldn't known to everyone
func (consensus *Consensus) GetPeerByAddress(validatorAddress string) *p2p.Peer {
v, ok := consensus.validators.Load(validatorAddress)
if !ok {
@ -290,6 +295,12 @@ func (consensus *Consensus) GetPeerByAddress(validatorAddress string) *p2p.Peer
return &value
}
// IsValidatorInCommittee returns whether the given validator BLS address is part of my committee
func (consensus *Consensus) IsValidatorInCommittee(validatorBlsAddress common.Address) bool {
_, ok := consensus.CommitteeAddresses[validatorBlsAddress]
return ok
}
// Verify the signature of the message are valid from the signer's public key.
func verifyMessageSig(signerPubKey *bls.PublicKey, message *msg_pb.Message) error {
signature := message.Signature
@ -374,8 +385,8 @@ func (consensus *Consensus) GetCommitSigsArray() []*bls.Sign {
// ResetState resets the state of the consensus
func (consensus *Consensus) ResetState() {
consensus.state = Finished
consensus.prepareSigs = map[string]*bls.Sign{}
consensus.commitSigs = map[string]*bls.Sign{}
consensus.prepareSigs = map[common.Address]*bls.Sign{}
consensus.commitSigs = map[common.Address]*bls.Sign{}
prepareBitmap, _ := bls_cosi.NewMask(consensus.PublicKeys, consensus.leader.ConsensusPubKey)
commitBitmap, _ := bls_cosi.NewMask(consensus.PublicKeys, consensus.leader.ConsensusPubKey)
@ -407,10 +418,13 @@ func (consensus *Consensus) AddPeers(peers []*p2p.Peer) int {
count := 0
for _, peer := range peers {
_, ok := consensus.validators.LoadOrStore(utils.GetAddressHex(peer.ConsensusPubKey), *peer)
_, ok := consensus.validators.LoadOrStore(utils.GetBlsAddress(peer.ConsensusPubKey).Hex(), *peer)
if !ok {
consensus.pubKeyLock.Lock()
if _, ok := consensus.CommitteeAddresses[peer.ConsensusPubKey.GetAddress()]; !ok {
consensus.PublicKeys = append(consensus.PublicKeys, peer.ConsensusPubKey)
consensus.CommitteeAddresses[peer.ConsensusPubKey.GetAddress()] = true
}
consensus.pubKeyLock.Unlock()
}
count++
@ -486,7 +500,7 @@ func (consensus *Consensus) DebugPrintValidators() {
consensus.validators.Range(func(k, v interface{}) bool {
if p, ok := v.(p2p.Peer); ok {
str2 := fmt.Sprintf("%s", p.ConsensusPubKey.Serialize())
utils.GetLogInstance().Debug("validator:", "IP", p.IP, "Port", p.Port, "address", utils.GetAddressHex(p.ConsensusPubKey), "Key", str2)
utils.GetLogInstance().Debug("validator:", "IP", p.IP, "Port", p.Port, "address", utils.GetBlsAddress(p.ConsensusPubKey), "Key", str2)
count++
return true
}
@ -499,6 +513,12 @@ func (consensus *Consensus) DebugPrintValidators() {
func (consensus *Consensus) UpdatePublicKeys(pubKeys []*bls.PublicKey) int {
consensus.pubKeyLock.Lock()
consensus.PublicKeys = append(pubKeys[:0:0], pubKeys...)
consensus.CommitteeAddresses = map[common.Address]bool{}
for _, pubKey := range consensus.PublicKeys {
consensus.CommitteeAddresses[utils.GetBlsAddress(pubKey)] = true
}
// TODO: use pubkey to identify leader rather than p2p.Peer.
consensus.leader = p2p.Peer{ConsensusPubKey: pubKeys[0]}
consensus.pubKeyLock.Unlock()
return len(consensus.PublicKeys)
@ -593,7 +613,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.DB, header *type
}
// GetSelfAddress returns the address in hex
func (consensus *Consensus) GetSelfAddress() string {
func (consensus *Consensus) GetSelfAddress() common.Address {
return consensus.SelfAddress
}
@ -637,8 +657,8 @@ func (consensus *Consensus) GetLeaderPubKey() *bls.PublicKey {
return consensus.leader.ConsensusPubKey
}
// GetNumPeers returns the length of PublicKeys
func (consensus *Consensus) GetNumPeers() int {
// GetNumValidators returns the length of PublicKeys
func (consensus *Consensus) GetNumValidators() int {
return len(consensus.PublicKeys)
}

@ -147,13 +147,13 @@ func (consensus *Consensus) startConsensus(newBlock *types.Block) {
func (consensus *Consensus) processPrepareMessage(message *msg_pb.Message) {
consensusMsg := message.GetConsensus()
pubKey, err := bls_cosi.BytesToBlsPublicKey(consensusMsg.SenderPubkey)
validatorPubKey, err := bls_cosi.BytesToBlsPublicKey(consensusMsg.SenderPubkey)
if err != nil {
utils.GetLogInstance().Debug("Failed to deserialize BLS public key", "error", err)
return
}
addrBytes := pubKey.GetAddress()
validatorAddress := common.BytesToAddress(addrBytes[:]).Hex()
addrBytes := validatorPubKey.GetAddress()
validatorAddress := common.BytesToAddress(addrBytes[:])
prepareSig := consensusMsg.Payload
@ -163,14 +163,12 @@ func (consensus *Consensus) processPrepareMessage(message *msg_pb.Message) {
consensus.mutex.Lock()
defer consensus.mutex.Unlock()
validatorPeer := consensus.GetPeerByAddress(validatorAddress)
if validatorPeer == nil {
if !consensus.IsValidatorInCommittee(validatorAddress) {
utils.GetLogInstance().Error("Invalid validator", "validatorAddress", validatorAddress)
return
}
if err := consensus.checkConsensusMessage(message, validatorPeer.ConsensusPubKey); err != nil {
if err := consensus.checkConsensusMessage(message, validatorPubKey); err != nil {
utils.GetLogInstance().Debug("Failed to check the validator message", "error", err, "validatorAddress", validatorAddress)
return
}
@ -195,14 +193,14 @@ func (consensus *Consensus) processPrepareMessage(message *msg_pb.Message) {
return
}
if !sign.VerifyHash(validatorPeer.ConsensusPubKey, consensus.blockHash[:]) {
if !sign.VerifyHash(validatorPubKey, consensus.blockHash[:]) {
utils.GetLogInstance().Error("Received invalid BLS signature", "validatorAddress", validatorAddress)
return
}
utils.GetLogInstance().Debug("Received new prepare signature", "numReceivedSoFar", len(prepareSigs), "validatorAddress", validatorAddress, "PublicKeys", len(consensus.PublicKeys))
prepareSigs[validatorAddress] = &sign
prepareBitmap.SetKey(validatorPeer.ConsensusPubKey, true) // Set the bitmap indicating that this validator signed.
prepareBitmap.SetKey(validatorPubKey, true) // Set the bitmap indicating that this validator signed.
targetState := PreparedDone
if len(prepareSigs) >= ((len(consensus.PublicKeys)*2)/3+1) && consensus.state < targetState {
@ -228,27 +226,25 @@ func (consensus *Consensus) processPrepareMessage(message *msg_pb.Message) {
func (consensus *Consensus) processCommitMessage(message *msg_pb.Message) {
consensusMsg := message.GetConsensus()
pubKey, err := bls_cosi.BytesToBlsPublicKey(consensusMsg.SenderPubkey)
validatorPubKey, err := bls_cosi.BytesToBlsPublicKey(consensusMsg.SenderPubkey)
if err != nil {
utils.GetLogInstance().Debug("Failed to deserialize BLS public key", "error", err)
return
}
addrBytes := pubKey.GetAddress()
validatorAddress := common.BytesToAddress(addrBytes[:]).Hex()
addrBytes := validatorPubKey.GetAddress()
validatorAddress := common.BytesToAddress(addrBytes[:])
commitSig := consensusMsg.Payload
consensus.mutex.Lock()
defer consensus.mutex.Unlock()
validatorPeer := consensus.GetPeerByAddress(validatorAddress)
if validatorPeer == nil {
if !consensus.IsValidatorInCommittee(validatorAddress) {
utils.GetLogInstance().Error("Invalid validator", "validatorAddress", validatorAddress)
return
}
if err := consensus.checkConsensusMessage(message, validatorPeer.ConsensusPubKey); err != nil {
if err := consensus.checkConsensusMessage(message, validatorPubKey); err != nil {
utils.GetLogInstance().Debug("Failed to check the validator message", "validatorAddress", validatorAddress)
return
}
@ -276,7 +272,7 @@ func (consensus *Consensus) processCommitMessage(message *msg_pb.Message) {
return
}
aggSig := bls_cosi.AggregateSig(consensus.GetPrepareSigsArray())
if !sign.VerifyHash(validatorPeer.ConsensusPubKey, append(aggSig.Serialize(), consensus.prepareBitmap.Bitmap...)) {
if !sign.VerifyHash(validatorPubKey, append(aggSig.Serialize(), consensus.prepareBitmap.Bitmap...)) {
utils.GetLogInstance().Error("Received invalid BLS signature", "validatorAddress", validatorAddress)
return
}
@ -284,7 +280,7 @@ func (consensus *Consensus) processCommitMessage(message *msg_pb.Message) {
utils.GetLogInstance().Debug("Received new commit message", "numReceivedSoFar", len(commitSigs), "validatorAddress", validatorAddress)
commitSigs[validatorAddress] = &sign
// Set the bitmap indicating that this validator signed.
commitBitmap.SetKey(validatorPeer.ConsensusPubKey, true)
commitBitmap.SetKey(validatorPubKey, true)
targetState := CommittedDone
if len(commitSigs) >= ((len(consensus.PublicKeys)*2)/3+1) && consensus.state != targetState {

@ -3,6 +3,8 @@ package consensus
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
protobuf "github.com/golang/protobuf/proto"
@ -53,8 +55,8 @@ func TestConstructPreparedMessage(test *testing.T) {
consensus.blockHash = [32]byte{}
message := "test string"
consensus.prepareSigs["0"] = leaderPriKey.Sign(message)
consensus.prepareSigs["1"] = validatorPriKey.Sign(message)
consensus.prepareSigs[common.Address{}] = leaderPriKey.Sign(message)
consensus.prepareSigs[common.Address{}] = validatorPriKey.Sign(message)
consensus.prepareBitmap.SetKey(leaderPubKey, true)
consensus.prepareBitmap.SetKey(validatorPubKey, true)

@ -4,6 +4,8 @@ import (
"bytes"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
@ -133,7 +135,7 @@ func TestSignAndMarshalConsensusMessage(t *testing.T) {
consensus := New(host, 0, []p2p.Peer{leader, validator}, leader, bls.RandPrivateKey())
consensus.consensusID = 2
consensus.blockHash = blockHash
consensus.SelfAddress = "fake address"
consensus.SelfAddress = common.Address{}
msg := &msg_pb.Message{}
marshaledMessage, err := consensus.signAndMarshalConsensusMessage(msg)

@ -68,7 +68,7 @@ func (consensus *Consensus) processAnnounceMessage(message *msg_pb.Message) {
consensus.block = block
if err := consensus.checkConsensusMessage(message, consensus.leader.ConsensusPubKey); err != nil {
utils.GetLogInstance().Debug("Failed to check the leader message", "key", utils.GetAddressHex(consensus.leader.ConsensusPubKey))
utils.GetLogInstance().Debug("Failed to check the leader message", "key", utils.GetBlsAddress(consensus.leader.ConsensusPubKey))
return
}

@ -7,17 +7,31 @@ import (
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = abi.U256
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
// LotteryABI is the input ABI used to generate the binding from.
const LotteryABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"manager\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"pickWinner\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getPlayers\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"enter\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"players\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"
// LotteryBin is the compiled bytecode used for deploying new contracts.
const LotteryBin = `0x608060405234801561001057600080fd5b5060008054600160a060020a03191633179055610568806100326000396000f3fe608060405260043610610066577c01000000000000000000000000000000000000000000000000000000006000350463481c6a75811461006b5780635d495aea1461009c5780638b5b9ccc146100a6578063e97dcb621461010b578063f71d96cb14610113575b600080fd5b34801561007757600080fd5b5061008061013d565b60408051600160a060020a039092168252519081900360200190f35b6100a461014c565b005b3480156100b257600080fd5b506100bb6102bf565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156100f75781810151838201526020016100df565b505050509050019250505060405180910390f35b6100a4610322565b34801561011f57600080fd5b506100806004803603602081101561013657600080fd5b5035610401565b600054600160a060020a031681565b60005460408051808201909152601381527f4f6e6c79206d616e616765722063616e20646f00000000000000000000000000602082015290600160a060020a03163314610231576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156101f65781810151838201526020016101de565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600154600090610240610429565b81151561024957fe5b06905060018181548110151561025b57fe5b6000918252602082200154604051600160a060020a0390911691303180156108fc02929091818181858888f1935050505015801561029d573d6000803e3d6000fd5b5060408051600081526020810191829052516102bb9160019161046d565b5050565b6060600180548060200260200160405190810160405280929190818152602001828054801561031757602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116102f9575b505050505090505b90565b67016345785d8a00003411606060405190810160405280602c8152602001610511602c91399015156103b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156101f65781810151838201526020016101de565b506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601805473ffffffffffffffffffffffffffffffffffffffff191633179055565b600180548290811061040f57fe5b600091825260209091200154600160a060020a0316905081565b60408051426020808301919091526c010000000000000000000000003381028385015230026054830152825160488184030181526068909201909252805191012090565b8280548282559060005260206000209081019282156104cf579160200282015b828111156104cf578251825473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390911617825560209092019160019091019061048d565b506104db9291506104df565b5090565b61031f91905b808211156104db57805473ffffffffffffffffffffffffffffffffffffffff191681556001016104e556fe54686520706c61796572206e6565647320746f207374616b65206174206c6561737420302e31206574686572a165627a7a72305820e9e057dfabaa0039b2b5c5a3eb3065c7a3058e47b289028b599918412f018e830029`
const LotteryBin = `0x608060405234801561001057600080fd5b50600080546001600160a01b031916331790556104ec806100326000396000f3fe60806040526004361061004a5760003560e01c8063481c6a751461004f5780635d495aea146100805780638b5b9ccc1461008a578063e97dcb62146100ef578063f71d96cb146100f7575b600080fd5b34801561005b57600080fd5b50610064610121565b604080516001600160a01b039092168252519081900360200190f35b610088610130565b005b34801561009657600080fd5b5061009f61028c565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156100db5781810151838201526020016100c3565b505050509050019250505060405180910390f35b6100886102ef565b34801561010357600080fd5b506100646004803603602081101561011a57600080fd5b50356103a9565b6000546001600160a01b031681565b60005460408051808201909152601381527f4f6e6c79206d616e616765722063616e20646f000000000000000000000000006020820152906001600160a01b031633146101fe57604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b838110156101c35781810151838201526020016101ab565b50505050905090810190601f1680156101f05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060015460009061020d6103d1565b81151561021657fe5b06905060018181548110151561022857fe5b60009182526020822001546040516001600160a01b0390911691303180156108fc02929091818181858888f1935050505015801561026a573d6000803e3d6000fd5b5060408051600081526020810191829052516102889160019161040b565b5050565b606060018054806020026020016040519081016040528092919081815260200182805480156102e457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116102c6575b505050505090505b90565b67016345785d8a000034116040518060600160405280602c8152602001610495602c913990151561036557604051600160e51b62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156101c35781810151838201526020016101ab565b506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191633179055565b60018054829081106103b757fe5b6000918252602090912001546001600160a01b0316905081565b604080514260208083019190915233606090811b8385015230901b6054830152825160488184030181526068909201909252805191012090565b828054828255906000526020600020908101928215610460579160200282015b8281111561046057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061042b565b5061046c929150610470565b5090565b6102ec91905b8082111561046c5780546001600160a01b031916815560010161047656fe54686520706c61796572206e6565647320746f207374616b65206174206c6561737420302e31206574686572a165627a7a72305820159638f94fdba6b1dc61d4071f6673028ee53a12a39d66f7ec00701aed93a0b60029`
// DeployLottery deploys a new Ethereum contract, binding an instance of Lottery to it.
func DeployLottery(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Lottery, error) {

File diff suppressed because one or more lines are too long

@ -7,7 +7,7 @@ contract StakeLockContract {
string internal constant ALREADY_LOCKED = 'Tokens already locked';
string internal constant NO_TOKEN_UNLOCKABLE = 'No tokens unlockable';
string internal constant AMOUNT_ZERO = 'Amount can not be 0';
string internal constant EMPTY_BLS_ADDRESS = 'BLS address should not be empty';
string internal constant EMPTY_BLS_PUBKEY = 'BLS public key should not be empty';
uint256 internal constant LOCK_PERIOD_IN_EPOCHS = 3; // Final locking period TBD.
@ -22,8 +22,10 @@ contract StakeLockContract {
uint256 _epochNum; // The epoch when the token was locked
uint256 _lockPeriodCount; // The number of locking period the token will be locked.
uint256 _index; // The index in the addressList
bytes20 _blsAddress; // The address of BLS account used for consensus message signing.
// TODO: the bls address should be signed by the bls key to prove the ownership.
bytes32 _blsPublicKey1; // The BLS public key divided into 3 32bytes chucks used for consensus message signing.
bytes32 _blsPublicKey2;
bytes32 _blsPublicKey3;
// TODO: the BLS public key should be signed by the bls key to prove the ownership.
}
/**
@ -40,21 +42,23 @@ contract StakeLockContract {
/**
* @dev Locks a specified amount of tokens against an address
* starting at the specific epoch
* @param _blsAddress The address of BLS key for consensus message signing
* @param _blsPublicKey1 The first part of BLS public key for consensus message signing
* @param _blsPublicKey2 The second part of BLS public key for consensus message signing
* @param _blsPublicKey3 The third part of BLS public key for consensus message signing
*/
function lock(bytes20 _blsAddress)
function lock(bytes32 _blsPublicKey1, bytes32 _blsPublicKey2, bytes32 _blsPublicKey3)
public
payable
returns (bool)
{
// If tokens are already locked, then functions extendLock or
// increaseLockAmount should be used to make any changes
require(_blsAddress != 0, EMPTY_BLS_ADDRESS);
// require(_blsPublicKey != 0, EMPTY_BLS_PUBKEY);
require(balanceOf(msg.sender) == 0, ALREADY_LOCKED);
require(msg.value != 0, AMOUNT_ZERO);
// By default, the tokens can only be locked for one locking period.
locked[msg.sender] = lockedToken(msg.value, block.number, currentEpoch(), 1, addressList.push(msg.sender) - 1, _blsAddress);
locked[msg.sender] = lockedToken(msg.value, block.number, currentEpoch(), 1, addressList.push(msg.sender) - 1, _blsPublicKey1, _blsPublicKey2, _blsPublicKey3);
emit Locked(msg.sender, msg.value, currentEpoch());
return true;
@ -123,16 +127,20 @@ contract StakeLockContract {
function listLockedAddresses()
public
view
returns (address[] memory lockedAddresses, bytes20[] memory blsAddresses, uint256[] memory blockNums, uint256[] memory lockPeriodCounts, uint256[] memory amounts)
returns (address[] memory lockedAddresses, bytes32[] memory blsPubicKeys1, bytes32[] memory blsPubicKeys2, bytes32[] memory blsPubicKeys3, uint256[] memory blockNums, uint256[] memory lockPeriodCounts, uint256[] memory amounts)
{
lockedAddresses = addressList;
blsAddresses = new bytes20[](addressList.length);
blsPubicKeys1 = new bytes32[](addressList.length);
blsPubicKeys2 = new bytes32[](addressList.length);
blsPubicKeys3 = new bytes32[](addressList.length);
blockNums = new uint256[](addressList.length);
lockPeriodCounts = new uint256[](addressList.length);
amounts = new uint256[](addressList.length);
for (uint i = 0; i < lockedAddresses.length; i++) {
blockNums[i] = locked[lockedAddresses[i]]._blockNum;
blsAddresses[i] = locked[lockedAddresses[i]]._blsAddress;
blsPubicKeys1[i] = locked[lockedAddresses[i]]._blsPublicKey1;
blsPubicKeys2[i] = locked[lockedAddresses[i]]._blsPublicKey2;
blsPubicKeys3[i] = locked[lockedAddresses[i]]._blsPublicKey3;
lockPeriodCounts[i] = locked[lockedAddresses[i]]._lockPeriodCount;
amounts[i] = locked[lockedAddresses[i]]._amount;
}

@ -1,3 +1,3 @@
abigen -sol Lottery.sol -out Lottery.go --pkg contracts
# abigen -sol Faucet.sol -out Faucet.go --pkg contracts
# abigen -sol StakeLockContract.sol -out StakeLockContract.go --pkg contracts
abigen -sol StakeLockContract.sol -out StakeLockContract.go --pkg contracts

@ -3,13 +3,17 @@ package structs
import (
"math/big"
"github.com/harmony-one/harmony/core/types"
"github.com/ethereum/go-ethereum/common"
)
// StakeInfoReturnValue is the struct for the return value of listLockedAddresses func in stake contract.
type StakeInfoReturnValue struct {
LockedAddresses []common.Address
BlsAddresses [][20]byte
BlsPubicKeys1 [][32]byte
BlsPubicKeys2 [][32]byte
BlsPubicKeys3 [][32]byte
BlockNums []*big.Int
LockPeriodCounts []*big.Int // The number of locking period the token will be locked.
Amounts []*big.Int
@ -17,7 +21,7 @@ type StakeInfoReturnValue struct {
// StakeInfo stores the staking information for a staker.
type StakeInfo struct {
BlsAddress [20]byte
BlsPublicKey types.BlsPublicKey
BlockNum *big.Int
LockPeriodCount *big.Int // The number of locking period the token will be locked.
Amount *big.Int

@ -70,7 +70,7 @@ const (
// BlocksPerEpoch is the number of blocks in one epoch
// currently set to small number for testing
// in future, this need to be adjusted dynamically instead of constant
BlocksPerEpoch = 10
BlocksPerEpoch = 5
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -1740,12 +1740,12 @@ func (bc *BlockChain) StoreNewShardState(block *types.Block, stakeInfo *map[comm
hash := block.Hash()
number := block.NumberU64()
rawdb.WriteShardState(bc.db, hash, number, shardState)
utils.GetLogInstance().Debug("[Resharding] Saved new shard state successfully")
utils.GetLogInstance().Debug("[Resharding] Saved new shard state successfully", "epoch", GetEpochFromBlockNumber(block.NumberU64()))
for _, shard := range shardState {
output := shard.Leader.BlsAddress
output := shard.Leader.BlsPublicKey.Hex()
output = output + " \n"
for _, node := range shard.NodeList {
output = output + node.BlsAddress + " \n"
output = output + node.BlsPublicKey.Hex() + " \n"
}
utils.GetLogInstance().Debug(fmt.Sprintf("[Resharding][shard: %d] Leader: %s", shard.ShardID, output))
}

@ -148,22 +148,6 @@ func CalculateNewShardState(bc *BlockChain, epoch uint64, stakeInfo *map[common.
return GetInitShardState()
}
ss := GetShardingStateFromBlockChain(bc, epoch-1)
if epoch == FirstEpoch {
newNodes := []types.NodeID{}
for addr, stakeInfo := range *stakeInfo {
blsAddr := common.BytesToAddress(stakeInfo.BlsAddress[:])
newNodes = append(newNodes, types.NodeID{addr.Hex(), blsAddr.Hex()})
}
rand.Seed(int64(ss.rnd))
Shuffle(newNodes)
utils.GetLogInstance().Info("[resharding] New Nodes", "data", newNodes)
for i, nid := range newNodes {
id := i%(GenesisShardNum-1) + 1 // assign the node to one of the empty shard
ss.shardState[id].NodeList = append(ss.shardState[id].NodeList, nid)
}
return ss.shardState
}
newNodeList := ss.UpdateShardingState(stakeInfo)
utils.GetLogInstance().Info("Cuckoo Rate", "percentage", CuckooRate)
ss.Reshard(newNodeList, CuckooRate)
@ -172,11 +156,11 @@ func CalculateNewShardState(bc *BlockChain, epoch uint64, stakeInfo *map[common.
// UpdateShardingState remove the unstaked nodes and returns the newly staked node Ids.
func (ss *ShardingState) UpdateShardingState(stakeInfo *map[common.Address]*structs.StakeInfo) []types.NodeID {
oldAddresses := make(map[string]bool) // map of bls addresses
oldBlsPublicKeys := make(map[types.BlsPublicKey]bool) // map of bls public keys
for _, shard := range ss.shardState {
newNodeList := shard.NodeList[:0]
for _, nodeID := range shard.NodeList {
oldAddresses[nodeID.BlsAddress] = true
oldBlsPublicKeys[nodeID.BlsPublicKey] = true
_, ok := (*stakeInfo)[common.HexToAddress(nodeID.EcdsaAddress)]
if ok {
newNodeList = append(newNodeList, nodeID)
@ -189,9 +173,9 @@ func (ss *ShardingState) UpdateShardingState(stakeInfo *map[common.Address]*stru
newAddresses := []types.NodeID{}
for addr, info := range *stakeInfo {
_, ok := oldAddresses[addr.Hex()]
_, ok := oldBlsPublicKeys[info.BlsPublicKey]
if !ok {
newAddresses = append(newAddresses, types.NodeID{addr.Hex(), common.BytesToAddress(info.BlsAddress[:]).Hex()})
newAddresses = append(newAddresses, types.NodeID{addr.Hex(), info.BlsPublicKey})
}
}
return newAddresses
@ -206,10 +190,10 @@ func GetInitShardState() types.ShardState {
index := i*GenesisShardSize + j // The initial account to use for genesis nodes
priKey := bls.SecretKey{}
priKey.SetHexString(contract.GenesisBLSAccounts[index].Private)
addrBytes := priKey.GetPublicKey().GetAddress()
blsAddr := common.BytesToAddress(addrBytes[:]).Hex()
pubKey := [96]byte{}
copy(pubKey[:], priKey.GetPublicKey().Serialize()[:])
// TODO: directly read address for bls too
curNodeID := types.NodeID{contract.GenesisAccounts[index].Address, blsAddr}
curNodeID := types.NodeID{contract.GenesisAccounts[index].Address, pubKey}
if j == 0 {
com.Leader = curNodeID
}

@ -10,6 +10,32 @@ import (
"github.com/stretchr/testify/assert"
)
var (
blsPubKey1 = [96]byte{}
blsPubKey2 = [96]byte{}
blsPubKey3 = [96]byte{}
blsPubKey4 = [96]byte{}
blsPubKey5 = [96]byte{}
blsPubKey6 = [96]byte{}
blsPubKey7 = [96]byte{}
blsPubKey8 = [96]byte{}
blsPubKey9 = [96]byte{}
blsPubKey10 = [96]byte{}
)
func init() {
copy(blsPubKey1[:], []byte("random key 1"))
copy(blsPubKey2[:], []byte("random key 2"))
copy(blsPubKey3[:], []byte("random key 3"))
copy(blsPubKey4[:], []byte("random key 4"))
copy(blsPubKey5[:], []byte("random key 5"))
copy(blsPubKey6[:], []byte("random key 6"))
copy(blsPubKey7[:], []byte("random key 7"))
copy(blsPubKey8[:], []byte("random key 8"))
copy(blsPubKey9[:], []byte("random key 9"))
copy(blsPubKey10[:], []byte("random key 10"))
}
func fakeGetInitShardState(numberOfShards, numOfNodes int) types.ShardState {
rand.Seed(int64(InitialSeed))
shardState := types.ShardState{}
@ -18,7 +44,9 @@ func fakeGetInitShardState(numberOfShards, numOfNodes int) types.ShardState {
com := types.Committee{ShardID: sid}
for j := 0; j < numOfNodes; j++ {
nid := strconv.Itoa(int(rand.Int63()))
com.NodeList = append(com.NodeList, types.NodeID{nid, nid})
blsPubKey := [96]byte{}
copy(blsPubKey1[:], []byte(nid))
com.NodeList = append(com.NodeList, types.NodeID{nid, blsPubKey})
}
shardState = append(shardState, com)
}
@ -31,7 +59,9 @@ func fakeNewNodeList(seed int64) []types.NodeID {
nodeList := []types.NodeID{}
for i := 0; i < numNewNodes; i++ {
nid := strconv.Itoa(int(rand.Int63()))
nodeList = append(nodeList, types.NodeID{nid, nid})
blsPubKey := [96]byte{}
copy(blsPubKey1[:], []byte(nid))
nodeList = append(nodeList, types.NodeID{nid, blsPubKey})
}
return nodeList
}
@ -43,16 +73,16 @@ func TestFakeNewNodeList(t *testing.T) {
func TestShuffle(t *testing.T) {
nodeList := []types.NodeID{
{"node1", "node1"},
{"node2", "node2"},
{"node3", "node3"},
{"node4", "node4"},
{"node5", "node5"},
{"node6", "node6"},
{"node7", "node7"},
{"node8", "node8"},
{"node9", "node9"},
{"node10", "node10"},
{"node1", blsPubKey1},
{"node2", blsPubKey2},
{"node3", blsPubKey3},
{"node4", blsPubKey4},
{"node5", blsPubKey5},
{"node6", blsPubKey6},
{"node7", blsPubKey7},
{"node8", blsPubKey8},
{"node9", blsPubKey9},
{"node10", blsPubKey10},
}
cpList := []types.NodeID{}
@ -83,18 +113,18 @@ func TestUpdateShardState(t *testing.T) {
shardState := fakeGetInitShardState(6, 10)
ss := &ShardingState{epoch: 1, rnd: 42, shardState: shardState, numShards: len(shardState)}
newNodeList := []types.NodeID{
{"node1", "node1"},
{"node2", "node2"},
{"node3", "node3"},
{"node4", "node4"},
{"node5", "node5"},
{"node6", "node6"},
{"node1", blsPubKey1},
{"node2", blsPubKey2},
{"node3", blsPubKey3},
{"node4", blsPubKey4},
{"node5", blsPubKey5},
{"node6", blsPubKey6},
}
ss.Reshard(newNodeList, 0.2)
assert.Equal(t, 6, ss.numShards)
for _, shard := range ss.shardState {
assert.Equal(t, shard.Leader.BlsAddress, shard.NodeList[0].BlsAddress)
assert.Equal(t, shard.Leader.BlsPublicKey, shard.NodeList[0].BlsPublicKey)
}
}
@ -102,9 +132,9 @@ func TestAssignNewNodes(t *testing.T) {
shardState := fakeGetInitShardState(2, 2)
ss := &ShardingState{epoch: 1, rnd: 42, shardState: shardState, numShards: len(shardState)}
newNodes := []types.NodeID{
{"node1", "node1"},
{"node2", "node2"},
{"node3", "node3"},
{"node1", blsPubKey1},
{"node2", blsPubKey2},
{"node3", blsPubKey3},
}
ss.assignNewNodes(newNodes)

@ -1,8 +1,9 @@
package types
import (
"bytes"
"encoding/hex"
"sort"
"strings"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/crypto/sha3"
@ -11,10 +12,13 @@ import (
// ShardState is the collection of all committees
type ShardState []Committee
// BlsPublicKey defines the bls public key
type BlsPublicKey [96]byte
// NodeID represents node id (BLS address).
type NodeID struct {
EcdsaAddress string
BlsAddress string
BlsPublicKey BlsPublicKey
}
// Committee contains the active nodes in one shard
@ -24,6 +28,11 @@ type Committee struct {
NodeList []NodeID
}
// Hex returns the hex string of bls public key
func (pk BlsPublicKey) Hex() string {
return hex.EncodeToString(pk[:])
}
// GetHashFromNodeList will sort the list, then use Keccak256 to hash the list
// notice that the input nodeList will be modified (sorted)
func GetHashFromNodeList(nodeList []NodeID) []byte {
@ -58,10 +67,10 @@ func (ss ShardState) Hash() (h common.Hash) {
// CompareNodeID compares two nodes by their ID; used to sort node list
func CompareNodeID(n1 NodeID, n2 NodeID) int {
return strings.Compare(n1.BlsAddress, n2.BlsAddress)
return bytes.Compare(n1.BlsPublicKey[:], n2.BlsPublicKey[:])
}
// Serialize serialize NodeID into bytes
func (n NodeID) Serialize() []byte {
return []byte(n.BlsAddress)
return append(n.BlsPublicKey[:], []byte(n.EcdsaAddress)...)
}

@ -5,16 +5,38 @@ import (
"testing"
)
var (
blsPubKey1 = [96]byte{}
blsPubKey2 = [96]byte{}
blsPubKey3 = [96]byte{}
blsPubKey4 = [96]byte{}
blsPubKey5 = [96]byte{}
blsPubKey6 = [96]byte{}
blsPubKey11 = [96]byte{}
blsPubKey22 = [96]byte{}
)
func init() {
copy(blsPubKey1[:], []byte("random key 1"))
copy(blsPubKey2[:], []byte("random key 2"))
copy(blsPubKey3[:], []byte("random key 3"))
copy(blsPubKey4[:], []byte("random key 4"))
copy(blsPubKey5[:], []byte("random key 5"))
copy(blsPubKey6[:], []byte("random key 6"))
copy(blsPubKey11[:], []byte("random key 11"))
copy(blsPubKey22[:], []byte("random key 22"))
}
func TestGetHashFromNodeList(t *testing.T) {
l1 := []NodeID{
{"node1", "node1"},
{"node2", "node2"},
{"node3", "node3"},
{"node1", blsPubKey1},
{"node2", blsPubKey2},
{"node3", blsPubKey3},
}
l2 := []NodeID{
{"node2", "node2"},
{"node1", "node1"},
{"node3", "node3"},
{"node2", blsPubKey2},
{"node1", blsPubKey1},
{"node3", blsPubKey3},
}
h1 := GetHashFromNodeList(l1)
h2 := GetHashFromNodeList(l2)
@ -27,20 +49,20 @@ func TestGetHashFromNodeList(t *testing.T) {
func TestHash(t *testing.T) {
com1 := Committee{
ShardID: 22,
Leader: NodeID{"node11", "node11"},
Leader: NodeID{"node11", blsPubKey11},
NodeList: []NodeID{
{"node11", "node11"},
{"node22", "node22"},
{"node1", "node1"},
{"node11", blsPubKey11},
{"node22", blsPubKey22},
{"node1", blsPubKey1},
},
}
com2 := Committee{
ShardID: 2,
Leader: NodeID{"node4", "node4"},
Leader: NodeID{"node4", blsPubKey4},
NodeList: []NodeID{
{"node4", "node4"},
{"node5", "node5"},
{"node6", "node6"},
{"node4", blsPubKey4},
{"node5", blsPubKey5},
{"node6", blsPubKey6},
},
}
shardState1 := ShardState{com1, com2}
@ -48,20 +70,20 @@ func TestHash(t *testing.T) {
com3 := Committee{
ShardID: 2,
Leader: NodeID{"node4", "node4"},
Leader: NodeID{"node4", blsPubKey4},
NodeList: []NodeID{
{"node6", "node6"},
{"node5", "node5"},
{"node4", "node4"},
{"node6", blsPubKey6},
{"node5", blsPubKey5},
{"node4", blsPubKey4},
},
}
com4 := Committee{
ShardID: 22,
Leader: NodeID{"node11", "node11"},
Leader: NodeID{"node11", blsPubKey11},
NodeList: []NodeID{
{"node1", "node1"},
{"node11", "node11"},
{"node22", "node22"},
{"node1", blsPubKey1},
{"node11", blsPubKey11},
{"node22", blsPubKey22},
},
}

@ -5,6 +5,8 @@ import (
"errors"
"sync"
"github.com/ethereum/go-ethereum/common"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/bls/ffi/go/bls"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
@ -18,7 +20,7 @@ import (
// DRand is the main struct which contains state for the distributed randomness protocol.
type DRand struct {
vrfs *map[string][]byte // Key is the address hex
vrfs *map[common.Address][]byte // Key is the address hex
bitmap *bls_cosi.Mask
pRand *[32]byte
rand *[32]byte
@ -38,6 +40,8 @@ type DRand struct {
// Public keys of the committee including leader and validators
PublicKeys []*bls.PublicKey
// The addresses of my committee
CommitteeAddresses map[common.Address]bool
pubKeyLock sync.Mutex
// private/public keys of current node
@ -52,7 +56,7 @@ type DRand struct {
IsLeader bool
// Leader or validator address
SelfAddress string
SelfAddress common.Address
// The p2p host used to send/receive p2p messages
host p2p.Host
@ -84,11 +88,13 @@ func New(host p2p.Host, ShardID uint32, peers []p2p.Peer, leader p2p.Peer, confi
}
dRand.leader = leader
dRand.CommitteeAddresses = map[common.Address]bool{}
for _, peer := range peers {
dRand.validators.Store(utils.GetAddressHex(peer.ConsensusPubKey), peer)
dRand.validators.Store(utils.GetBlsAddress(peer.ConsensusPubKey).Hex(), peer)
dRand.CommitteeAddresses[utils.GetBlsAddress(peer.ConsensusPubKey)] = true
}
dRand.vrfs = &map[string][]byte{}
dRand.vrfs = &map[common.Address][]byte{}
// Initialize cosign bitmap
allPublicKeys := make([]*bls.PublicKey, 0)
@ -106,7 +112,7 @@ func New(host p2p.Host, ShardID uint32, peers []p2p.Peer, leader p2p.Peer, confi
dRand.rand = nil
// For now use socket address as ID
dRand.SelfAddress = utils.GetAddressHex(selfPeer.ConsensusPubKey)
dRand.SelfAddress = utils.GetBlsAddress(selfPeer.ConsensusPubKey)
// Set private key for myself so that I can sign messages.
if blsPriKey != nil {
@ -129,10 +135,13 @@ func (dRand *DRand) AddPeers(peers []*p2p.Peer) int {
count := 0
for _, peer := range peers {
_, ok := dRand.validators.LoadOrStore(utils.GetAddressHex(peer.ConsensusPubKey), *peer)
_, ok := dRand.validators.LoadOrStore(utils.GetBlsAddress(peer.ConsensusPubKey).Hex(), *peer)
if !ok {
dRand.pubKeyLock.Lock()
if _, ok := dRand.CommitteeAddresses[peer.ConsensusPubKey.GetAddress()]; !ok {
dRand.PublicKeys = append(dRand.PublicKeys, peer.ConsensusPubKey)
dRand.CommitteeAddresses[peer.ConsensusPubKey.GetAddress()] = true
}
dRand.pubKeyLock.Unlock()
// utils.GetLogInstance().Debug("[DRAND]", "AddPeers", *peer)
}
@ -226,9 +235,15 @@ func (dRand *DRand) getValidatorPeerByAddress(validatorAddress string) *p2p.Peer
return &value
}
// IsValidatorInCommittee returns whether the given validator BLS address is part of my committee
func (dRand *DRand) IsValidatorInCommittee(validatorBlsAddress common.Address) bool {
_, ok := dRand.CommitteeAddresses[validatorBlsAddress]
return ok
}
// ResetState resets the state of the randomness protocol
func (dRand *DRand) ResetState() {
dRand.vrfs = &map[string][]byte{}
dRand.vrfs = &map[common.Address][]byte{}
bitmap, _ := bls_cosi.NewMask(dRand.PublicKeys, dRand.leader.ConsensusPubKey)
dRand.bitmap = bitmap
@ -246,6 +261,12 @@ func (dRand *DRand) SetLeaderPubKey(k []byte) error {
func (dRand *DRand) UpdatePublicKeys(pubKeys []*bls.PublicKey) int {
dRand.pubKeyLock.Lock()
dRand.PublicKeys = append(pubKeys[:0:0], pubKeys...)
dRand.CommitteeAddresses = map[common.Address]bool{}
for _, pubKey := range dRand.PublicKeys {
dRand.CommitteeAddresses[utils.GetBlsAddress(pubKey)] = true
}
// TODO: use pubkey to identify leader rather than p2p.Peer.
dRand.leader = p2p.Peer{ConsensusPubKey: pubKeys[0]}
dRand.pubKeyLock.Unlock()
return len(dRand.PublicKeys)

@ -4,7 +4,6 @@ import (
"bytes"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
protobuf "github.com/golang/protobuf/proto"
@ -116,10 +115,13 @@ func (dRand *DRand) processCommitMessage(message *msg_pb.Message) {
utils.GetLogInstance().Debug("Failed to deserialize BLS public key", "error", err)
return
}
addrBytes := senderPubKey.GetAddress()
validatorAddress := common.BytesToAddress(addrBytes[:]).Hex()
validatorAddress := utils.GetBlsAddress(senderPubKey)
if !dRand.IsValidatorInCommittee(validatorAddress) {
utils.GetLogInstance().Error("Invalid validator", "validatorAddress", validatorAddress)
return
}
validatorPeer := dRand.getValidatorPeerByAddress(validatorAddress)
vrfs := dRand.vrfs
if len((*vrfs)) >= ((len(dRand.PublicKeys))/3 + 1) {
utils.GetLogInstance().Debug("Received additional randomness commit message", "validatorAddress", validatorAddress)
@ -127,9 +129,9 @@ func (dRand *DRand) processCommitMessage(message *msg_pb.Message) {
}
// Verify message signature
err = verifyMessageSig(validatorPeer.ConsensusPubKey, message)
err = verifyMessageSig(senderPubKey, message)
if err != nil {
utils.GetLogInstance().Warn("[DRAND] failed to verify the message signature", "Error", err, "PubKey", validatorPeer.ConsensusPubKey)
utils.GetLogInstance().Warn("[DRAND] failed to verify the message signature", "Error", err, "PubKey", senderPubKey)
return
}
@ -149,7 +151,7 @@ func (dRand *DRand) processCommitMessage(message *msg_pb.Message) {
utils.GetLogInstance().Debug("Received new VRF commit", "numReceivedSoFar", len((*vrfs)), "validatorAddress", validatorAddress, "PublicKeys", len(dRand.PublicKeys))
(*vrfs)[validatorAddress] = drandMsg.Payload
dRand.bitmap.SetKey(validatorPeer.ConsensusPubKey, true) // Set the bitmap indicating that this validator signed.
dRand.bitmap.SetKey(senderPubKey, true) // Set the bitmap indicating that this validator signed.
if len((*vrfs)) >= ((len(dRand.PublicKeys))/3 + 1) {
// Construct pRand and initiate consensus on it

@ -226,10 +226,10 @@ func IsPrivateIP(ip net.IP) bool {
return false
}
// GetAddressHex returns the hex string of the address of consensus pubKey.
func GetAddressHex(key *bls.PublicKey) string {
// GetBlsAddress returns the address of consensus BLS pubKey.
func GetBlsAddress(key *bls.PublicKey) common.Address {
addr := common.Address{}
addrBytes := key.GetAddress()
addr.SetBytes(addrBytes[:])
return addr.Hex()
return addr
}

@ -207,7 +207,7 @@ func TestStringsToPeers(t *testing.T) {
}
}
func TestGetAddressHex(t *testing.T) {
func TestGetBlsAddress(t *testing.T) {
pubKey1 := pki.GetBLSPrivateKeyFromInt(333).GetPublicKey()
pubKey2 := pki.GetBLSPrivateKeyFromInt(1024).GetPublicKey()
tests := []struct {
@ -225,8 +225,8 @@ func TestGetAddressHex(t *testing.T) {
}
for _, test := range tests {
result := GetAddressHex(test.key)
if result != test.expected {
result := GetBlsAddress(test.key)
if result.Hex() != test.expected {
t.Errorf("Hex Of %v is: %v, got: %v", test.key, test.expected, result)
}
}

@ -8,6 +8,8 @@ import (
"sync"
"time"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
@ -256,8 +258,6 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database, is
os.Exit(1)
}
node.blockchain = chain
// Store the genesis shard state into db.
node.blockchain.StoreNewShardState(node.blockchain.CurrentBlock(), nil)
node.BlockChannel = make(chan *types.Block)
node.ConfirmedBlockChannel = make(chan *types.Block)
@ -278,6 +278,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database, is
} else {
node.AddContractKeyAndAddress()
}
}
node.ContractCaller = contracts.NewContractCaller(&db, node.blockchain, params.TestChainConfig)
@ -311,6 +312,26 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database, is
return &node
}
// InitGenesisShardState initialize genesis shard state and update committee pub keys for consensus and drand
func (node *Node) InitGenesisShardState() {
// Store the genesis shard state into db.
shardState := node.blockchain.StoreNewShardState(node.blockchain.CurrentBlock(), nil)
// Update validator public keys
for _, shard := range shardState {
if shard.ShardID == node.Consensus.ShardID {
pubKeys := []*bls.PublicKey{}
for _, node := range shard.NodeList {
blsPubKey := &bls.PublicKey{}
blsPubKey.Deserialize(node.BlsPublicKey[:])
pubKeys = append(pubKeys, blsPubKey)
}
node.Consensus.UpdatePublicKeys(pubKeys)
node.DRand.UpdatePublicKeys(pubKeys)
break
}
}
}
// AddPeers adds neighbors nodes
func (node *Node) AddPeers(peers []*p2p.Peer) int {
count := 0
@ -327,6 +348,7 @@ func (node *Node) AddPeers(peers []*p2p.Peer) int {
// Only leader needs to add the peer info into consensus
// Validators will receive the updated peer info from Leader via pong message
// TODO: remove this after fully migrating to beacon chain-based committee membership
if count > 0 && node.NodeConfig.IsLeader() {
node.Consensus.AddPeers(peers)
// TODO: make peers into a context object shared by consensus and drand

@ -3,6 +3,7 @@ package node
import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math"
"os"
@ -98,10 +99,10 @@ func (node *Node) messageHandler(content []byte, sender string) {
case proto.Consensus:
msgPayload, _ := proto.GetConsensusMessagePayload(content)
if consensusObj.IsLeader {
// utils.GetLogInstance().Info("NET: Leader received consensus message")
utils.GetLogInstance().Info("NET: Leader received consensus message")
consensusObj.ProcessMessageLeader(msgPayload)
} else {
// utils.GetLogInstance().Info("NET: Validator received consensus message")
utils.GetLogInstance().Info("NET: Validator received consensus message")
consensusObj.ProcessMessageValidator(msgPayload)
// TODO(minhdoan): add logic to check if the current blockchain is not sync with other consensus
// we should switch to other state rather than DoingConsensus.
@ -303,10 +304,10 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
if shardState != nil {
myShard := uint32(math.MaxUint32)
isLeader := false
blsAddr := node.Consensus.SelfAddress
myBlsPubKey := node.Consensus.PubKey.Serialize()
for _, shard := range shardState {
for _, nodeID := range shard.NodeList {
if nodeID.BlsAddress == blsAddr {
if bytes.Compare(nodeID.BlsPublicKey[:], myBlsPubKey) == 0 {
myShard = shard.ShardID
isLeader = shard.Leader == nodeID
}
@ -327,12 +328,12 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
}
}
if node.blockchain.ShardID() == myShard {
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] I stay at shard %d, %s", core.GetEpochFromBlockNumber(newBlock.NumberU64()), myShard, aboutLeader), "BlsAddress", blsAddr)
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] I stay at shard %d, %s", core.GetEpochFromBlockNumber(newBlock.NumberU64()), myShard, aboutLeader), "BlsPubKey", hex.EncodeToString(myBlsPubKey))
} else {
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] I got resharded to shard %d, %s", core.GetEpochFromBlockNumber(newBlock.NumberU64()), myShard, aboutLeader), "BlsAddress", blsAddr)
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] I got resharded to shard %d from shard %d, %s", core.GetEpochFromBlockNumber(newBlock.NumberU64()), myShard, node.blockchain.ShardID(), aboutLeader), "BlsPubKey", hex.EncodeToString(myBlsPubKey))
}
} else {
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] Somehow I got kicked out", core.GetEpochFromBlockNumber(newBlock.NumberU64())), "BlsAddress", blsAddr)
utils.GetLogInstance().Info(fmt.Sprintf("[Resharded][epoch:%d] Somehow I got kicked out", core.GetEpochFromBlockNumber(newBlock.NumberU64())), "BlsPubKey", hex.EncodeToString(myBlsPubKey))
}
}
}
@ -388,7 +389,7 @@ func (node *Node) pingMessageHandler(msgPayload []byte, sender string) int {
node.ClientPeer = peer
} else {
node.AddPeers([]*p2p.Peer{peer})
utils.GetLogInstance().Info("Add Peer to Node", "Address", node.Consensus.GetSelfAddress(), "Peer", peer, "# Peers", node.Consensus.GetNumPeers())
utils.GetLogInstance().Info("Add Peer to Node", "Address", node.Consensus.GetSelfAddress(), "Peer", peer, "# Peers", node.Consensus.GetNumValidators())
}
return 1
@ -396,6 +397,7 @@ func (node *Node) pingMessageHandler(msgPayload []byte, sender string) int {
// SendPongMessage is the a goroutine to periodcally send pong message to all peers
func (node *Node) SendPongMessage() {
utils.GetLogInstance().Info("Starting Pong routing")
tick := time.NewTicker(2 * time.Second)
tick2 := time.NewTicker(120 * time.Second)
@ -410,10 +412,11 @@ func (node *Node) SendPongMessage() {
case <-tick.C:
peers := node.Consensus.GetValidatorPeers()
numPeersNow := len(peers)
numPubKeysNow := node.Consensus.GetNumPeers()
numPubKeysNow := node.Consensus.GetNumValidators()
// no peers, wait for another tick
if numPeersNow == 0 || numPubKeysNow == 0 {
if numPubKeysNow == 0 {
utils.GetLogInstance().Info("[PONG] no peers, continue", "numPeers", numPeers, "numPeersNow", numPeersNow)
continue
}
// new peers added
@ -440,6 +443,7 @@ func (node *Node) SendPongMessage() {
// only need to notify consensus leader once to start the consensus
if firstTime {
// Leader stops sending ping message
time.Sleep(5 * time.Second)
node.serviceManager.TakeAction(&service.Action{Action: service.Stop, ServiceType: service.PeerDiscovery})
node.startConsensus <- struct{}{}
firstTime = false
@ -480,17 +484,18 @@ func (node *Node) pongMessageHandler(msgPayload []byte) int {
// set the leader pub key is the first thing to do
// otherwise, we may not be able to validate the consensus messages received
// which will result in first consensus timeout
// TODO: remove this after fully migrating to beacon chain-based committee membership
err = node.Consensus.SetLeaderPubKey(pong.LeaderPubKey)
if err != nil {
utils.GetLogInstance().Error("Unmarshal Consensus Leader PubKey Failed", "error", err)
} else {
utils.GetLogInstance().Info("Set Consensus Leader PubKey", "key", utils.GetAddressHex(node.Consensus.GetLeaderPubKey()))
utils.GetLogInstance().Info("Set Consensus Leader PubKey", "key", node.Consensus.GetLeaderPubKey())
}
err = node.DRand.SetLeaderPubKey(pong.LeaderPubKey)
if err != nil {
utils.GetLogInstance().Error("Unmarshal DRand Leader PubKey Failed", "error", err)
} else {
utils.GetLogInstance().Info("Set DRand Leader PubKey", "key", utils.GetAddressHex(node.Consensus.GetLeaderPubKey()))
utils.GetLogInstance().Info("Set DRand Leader PubKey", "key", node.Consensus.GetLeaderPubKey())
}
peers := make([]*p2p.Peer, 0)
@ -541,5 +546,7 @@ func (node *Node) pongMessageHandler(msgPayload []byte) int {
data["peer"] = p2p.GroupAction{Name: node.NodeConfig.GetShardGroupID(), Action: p2p.ActionPause}
node.serviceManager.TakeAction(&service.Action{Action: service.Notify, ServiceType: service.PeerDiscovery, Params: data})
// TODO: remove this after fully migrating to beacon chain-based committee membership
return node.Consensus.UpdatePublicKeys(publicKeys) + node.DRand.UpdatePublicKeys(publicKeys)
}

@ -63,6 +63,7 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan
// TODO(minhdoan): only happens for beaconchain
node.addNewShardStateHash(block)
newBlock = block
utils.GetLogInstance().Debug("Successfully proposed new block", "blockNum", block.NumberU64(), "numTxs", block.Transactions().Len())
break
}
}

@ -26,7 +26,7 @@ func (node *Node) setupForShardLeader() {
node.serviceManager.RegisterService(service.NetworkInfo, networkinfo.New(node.host, node.NodeConfig.GetShardGroupID(), chanPeer, nil))
// Register explorer service.
node.serviceManager.RegisterService(service.SupportExplorer, explorer.New(&node.SelfPeer, node.Consensus.GetNumPeers))
node.serviceManager.RegisterService(service.SupportExplorer, explorer.New(&node.SelfPeer, node.Consensus.GetNumValidators))
// Register consensus service.
node.serviceManager.RegisterService(service.Consensus, consensus.New(node.BlockChannel, node.Consensus, node.startConsensus))
// Register new block service.
@ -70,7 +70,7 @@ func (node *Node) setupForBeaconLeader() {
// Register randomness service
node.serviceManager.RegisterService(service.Randomness, randomness.New(node.DRand))
// Register explorer service.
node.serviceManager.RegisterService(service.SupportExplorer, explorer.New(&node.SelfPeer, node.Consensus.GetNumPeers))
node.serviceManager.RegisterService(service.SupportExplorer, explorer.New(&node.SelfPeer, node.Consensus.GetNumValidators))
}
func (node *Node) setupForBeaconValidator() {

@ -5,6 +5,8 @@ import (
"math/big"
"os"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core"
@ -44,8 +46,12 @@ func (node *Node) UpdateStakingList(stakeInfoReturnValue *structs.StakeInfoRetur
}
// True if the token is still staked within the locking period.
if curEpoch-startEpoch <= lockPeriodCount.Uint64()*lockPeriodInEpochs {
blsPubKey := types.BlsPublicKey{}
copy(blsPubKey[:32], stakeInfoReturnValue.BlsPubicKeys1[i][:])
copy(blsPubKey[32:64], stakeInfoReturnValue.BlsPubicKeys2[i][:])
copy(blsPubKey[64:96], stakeInfoReturnValue.BlsPubicKeys2[i][:])
node.CurrentStakes[addr] = &structs.StakeInfo{
stakeInfoReturnValue.BlsAddresses[i],
blsPubKey,
blockNum,
lockPeriodCount,
stakeInfoReturnValue.Amounts[i],

@ -20,7 +20,9 @@ var (
blockNum = big.NewInt(15000)
lockPeriodCount = big.NewInt(1)
testAddress = common.Address{123}
testBlsAddress = common.Address{132}.Bytes() // [20]byte
testBlsPubKey1 = [32]byte{}
testBlsPubKey2 = [32]byte{}
testBlsPubKey3 = [32]byte{}
)
func TestUpdateStakingList(t *testing.T) {
@ -45,7 +47,9 @@ func TestUpdateStakingList(t *testing.T) {
stakeInfo := &structs.StakeInfoReturnValue{
[]common.Address{testAddress},
[][20]byte{testAddress},
[][32]byte{testBlsPubKey1},
[][32]byte{testBlsPubKey2},
[][32]byte{testBlsPubKey3},
[]*big.Int{blockNum},
[]*big.Int{lockPeriodCount},
[]*big.Int{amount},

Loading…
Cancel
Save