Merge pull request #549 from harmony-one/rj_branch

Add Bls Key into staking contract; Let new node to read hard-coded keys
pull/554/head
Rongjian Lan 6 years ago committed by GitHub
commit 644a37f2c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      api/service/staking/service.go
  2. 38
      contracts/StakeLockContract.go
  3. 13
      contracts/StakeLockContract.sol
  4. 4
      node/contract.go
  5. 5
      node/node.go
  6. 2
      node/service_setup.go
  7. 37
      node/staking.go
  8. 6
      node/staking_test.go

@ -47,6 +47,7 @@ type Service struct {
stopChan chan struct{}
stoppedChan chan struct{}
accountKey *ecdsa.PrivateKey
blsAddress [20]byte
stakingAmount int64
state State
beaconChain *core.BlockChain
@ -54,12 +55,13 @@ type Service struct {
}
// New returns staking service.
func New(host p2p.Host, accountKey *ecdsa.PrivateKey, beaconChain *core.BlockChain) *Service {
func New(host p2p.Host, accountKey *ecdsa.PrivateKey, beaconChain *core.BlockChain, blsAddress [20]byte) *Service {
return &Service{
host: host,
stopChan: make(chan struct{}),
stoppedChan: make(chan struct{}),
accountKey: accountKey,
blsAddress: blsAddress,
stakingAmount: StakingAmount,
beaconChain: beaconChain,
}
@ -184,7 +186,8 @@ func (s *Service) createRawStakingMessage() []byte {
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
}
bytesData, err := abi.Pack("lock")
// TODO: the bls address should be signed by the bls private key
bytesData, err := abi.Pack("lock", s.blsAddress)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
}

File diff suppressed because one or more lines are too long

@ -7,6 +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';
uint256 internal constant LOCK_PERIOD_IN_EPOCHS = 3; // Final locking period TBD.
@ -21,6 +22,8 @@ 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.
}
/**
@ -37,19 +40,21 @@ 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
*/
function lock()
function lock(bytes20 _blsAddress)
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(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);
locked[msg.sender] = lockedToken(msg.value, block.number, currentEpoch(), 1, addressList.push(msg.sender) - 1, _blsAddress);
emit Locked(msg.sender, msg.value, currentEpoch());
return true;
@ -118,14 +123,16 @@ contract StakeLockContract {
function listLockedAddresses()
public
view
returns (address[] memory lockedAddresses, uint256[] memory blockNums, uint256[] memory lockPeriodCounts, uint256[] memory amounts)
returns (address[] memory lockedAddresses, bytes20[] memory blsAddresses, uint256[] memory blockNums, uint256[] memory lockPeriodCounts, uint256[] memory amounts)
{
lockedAddresses = addressList;
blsAddresses = new bytes20[](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;
lockPeriodCounts[i] = locked[lockedAddresses[i]]._lockPeriodCount;
amounts[i] = locked[lockedAddresses[i]]._amount;
}

@ -59,7 +59,7 @@ func (node *Node) generateDeployedStakingContractAddress(contractAddress common.
}
// QueryStakeInfo queries the stake info from the stake contract.
func (node *Node) QueryStakeInfo() *StakeInfo {
func (node *Node) QueryStakeInfo() *StakeInfoReturnValue {
abi, err := abi.JSON(strings.NewReader(contracts.StakeLockContractABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
@ -96,7 +96,7 @@ func (node *Node) QueryStakeInfo() *StakeInfo {
return nil
}
ret := &StakeInfo{}
ret := &StakeInfoReturnValue{}
err = abi.Unpack(ret, "listLockedAddresses", output)

@ -5,7 +5,6 @@ import (
"crypto/ecdsa"
"encoding/binary"
"fmt"
"math/big"
"os"
"sync"
"time"
@ -138,7 +137,7 @@ type Node struct {
serviceManager *service.Manager
//Staked Accounts and Contract
CurrentStakes map[common.Address]*big.Int //This will save the latest information about staked nodes.
CurrentStakes map[common.Address]*StakeInfo //This will save the latest information about staked nodes.
StakingContractAddress common.Address
WithdrawStakeFunc []byte
@ -252,7 +251,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database) *N
// Setup one time smart contracts
node.AddFaucetContractToPendingTransactions()
node.CurrentStakes = make(map[common.Address]*big.Int)
node.CurrentStakes = make(map[common.Address]*StakeInfo)
node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked
}

@ -79,7 +79,7 @@ func (node *Node) setupForNewNode() {
nodeConfig, chanPeer := node.initNodeConfiguration()
// Register staking service.
node.serviceManager.RegisterService(service.Staking, staking.New(node.host, node.AccountKey, node.beaconChain))
node.serviceManager.RegisterService(service.Staking, staking.New(node.host, node.AccountKey, node.beaconChain, node.NodeConfig.ConsensusPubKey.GetAddress()))
// Register peer discovery service. "0" is the beacon shard ID
node.serviceManager.RegisterService(service.PeerDiscovery, discovery.New(node.host, nodeConfig, chanPeer, node.AddBeaconPeer))
// Register networkinfo service. "0" is the beacon shard ID

@ -24,22 +24,30 @@ const (
lockPeriodInEpochs = 3 // This should be in sync with contracts/StakeLockContract.sol
)
// StakeInfo is the struct for the return value of listLockedAddresses func in stake contract.
type StakeInfo struct {
// StakeInfoReturnValue is the struct for the return value of listLockedAddresses func in stake contract.
type StakeInfoReturnValue struct {
LockedAddresses []common.Address
BlsAddresses [][20]byte
BlockNums []*big.Int
LockPeriodCounts []*big.Int // The number of locking period the token will be locked.
Amounts []*big.Int
}
// StakeInfo stores the staking information for a staker.
type StakeInfo struct {
BlsAddress [20]byte
BlockNum *big.Int
LockPeriodCount *big.Int // The number of locking period the token will be locked.
Amount *big.Int
}
// UpdateStakingList updates staking information by querying the staking smart contract.
func (node *Node) UpdateStakingList(stakeInfo *StakeInfo) {
node.CurrentStakes = make(map[common.Address]*big.Int)
if stakeInfo != nil {
for i, addr := range stakeInfo.LockedAddresses {
blockNum := stakeInfo.BlockNums[i]
lockPeriodCount := stakeInfo.LockPeriodCounts[i]
amount := stakeInfo.Amounts[i]
func (node *Node) UpdateStakingList(stakeInfoReturnValue *StakeInfoReturnValue) {
node.CurrentStakes = make(map[common.Address]*StakeInfo)
if stakeInfoReturnValue != nil {
for i, addr := range stakeInfoReturnValue.LockedAddresses {
blockNum := stakeInfoReturnValue.BlockNums[i]
lockPeriodCount := stakeInfoReturnValue.LockPeriodCounts[i]
startEpoch := core.GetEpochFromBlockNumber(blockNum.Uint64())
curEpoch := core.GetEpochFromBlockNumber(node.blockchain.CurrentBlock().NumberU64())
@ -48,7 +56,12 @@ func (node *Node) UpdateStakingList(stakeInfo *StakeInfo) {
continue // The token are counted into stakes at the beginning of next epoch.
}
if curEpoch-startEpoch <= lockPeriodCount.Uint64()*lockPeriodInEpochs {
node.CurrentStakes[addr] = amount
node.CurrentStakes[addr] = &StakeInfo{
stakeInfoReturnValue.BlsAddresses[i],
blockNum,
lockPeriodCount,
stakeInfoReturnValue.Amounts[i],
}
}
}
}
@ -57,8 +70,8 @@ func (node *Node) UpdateStakingList(stakeInfo *StakeInfo) {
func (node *Node) printStakingList() {
utils.GetLogInstance().Info("\n")
utils.GetLogInstance().Info("CURRENT STAKING INFO [START] ------------------------------------")
for addr, stake := range node.CurrentStakes {
utils.GetLogInstance().Info("", "Address", addr, "Stake", stake)
for addr, stakeInfo := range node.CurrentStakes {
utils.GetLogInstance().Info("", "Address", addr, "StakeInfo", stakeInfo)
}
utils.GetLogInstance().Info("CURRENT STAKING INFO [END} ------------------------------------")
utils.GetLogInstance().Info("\n")

@ -16,6 +16,7 @@ var (
blockNum = big.NewInt(15000)
lockPeriodCount = big.NewInt(1)
testAddress = common.Address{123}
testBlsAddress = common.Address{132}.Bytes() // [20]byte
)
func TestUpdateStakingList(t *testing.T) {
@ -39,8 +40,9 @@ func TestUpdateStakingList(t *testing.T) {
node.AddNewBlock(block)
}
stakeInfo := &StakeInfo{
stakeInfo := &StakeInfoReturnValue{
[]common.Address{testAddress},
[][20]byte{testAddress},
[]*big.Int{blockNum},
[]*big.Int{lockPeriodCount},
[]*big.Int{amount},
@ -48,7 +50,7 @@ func TestUpdateStakingList(t *testing.T) {
node.UpdateStakingList(stakeInfo)
if node.CurrentStakes[testAddress].Cmp(amount) != 0 {
if node.CurrentStakes[testAddress].Amount.Cmp(amount) != 0 {
t.Error("Stake Info is not updated correctly")
}
}

Loading…
Cancel
Save