diff --git a/api/service/discovery/service.go b/api/service/discovery/service.go index 293080ef3..1f22c5bd0 100644 --- a/api/service/discovery/service.go +++ b/api/service/discovery/service.go @@ -139,7 +139,7 @@ func (s *Service) contactP2pPeers() { if err != nil { utils.GetLogInstance().Error("[DISCOVERY] Failed to send ping message", "group", g) } else { - utils.GetLogInstance().Info("[DISCOVERY]", "Sent Ping Message", g) + //utils.GetLogInstance().Info("[DISCOVERY]", "Sent Ping Message", g) } } } diff --git a/api/service/staking/service.go b/api/service/staking/service.go index 610f1c9e3..f37f6beb4 100644 --- a/api/service/staking/service.go +++ b/api/service/staking/service.go @@ -2,7 +2,6 @@ package staking import ( "crypto/ecdsa" - "fmt" "math/big" "time" @@ -30,6 +29,8 @@ const ( WaitTime = 5 * time.Second // StakingContractAddress is the staking deployed contract address StakingContractAddress = "TODO(minhdoan): Create a PR to generate staking contract address" + // StakingAmount is the amount of stake to put + StakingAmount = 10 ) // State is the state of staking service. @@ -50,13 +51,13 @@ type Service struct { } // New returns staking service. -func New(host p2p.Host, accountKey *ecdsa.PrivateKey, stakingAmount int64, beaconChain *core.BlockChain) *Service { +func New(host p2p.Host, accountKey *ecdsa.PrivateKey, beaconChain *core.BlockChain) *Service { return &Service{ host: host, stopChan: make(chan struct{}), stoppedChan: make(chan struct{}), accountKey: accountKey, - stakingAmount: stakingAmount, + stakingAmount: StakingAmount, beaconChain: beaconChain, } } @@ -82,6 +83,7 @@ func (s *Service) Run() { return } s.DoService() + return case <-s.stopChan: return } @@ -135,9 +137,14 @@ func (s *Service) getStakingInfo() *proto.StakingContractInfoResponse { func (s *Service) getFakeStakingInfo() *proto.StakingContractInfoResponse { balance := big.NewInt(params.Ether) - nonce := uint64(0) + nonce := uint64(0) // TODO: make it a incrementing field + + priKey := contract_constants.GenesisBeaconAccountPriKey + contractAddress := crypto.PubkeyToAddress(priKey.PublicKey) + + stakingContractAddress := crypto.CreateAddress(contractAddress, uint64(nonce)) return &proto.StakingContractInfoResponse{ - ContractAddress: fmt.Sprintf("%s", contract_constants.DeployedContractAddress), + ContractAddress: stakingContractAddress.Hex(), Balance: balance.Bytes(), Nonce: nonce, } @@ -173,9 +180,9 @@ func (s *Service) createRawStakingMessage() []byte { toAddress, 0, // beacon chain. big.NewInt(s.stakingAmount), - params.CallValueTransferGas*2, // hard-code - big.NewInt(int64(params.Sha256BaseGas)), // pick some predefined gas price. - nil) + params.TxGas*10, // hard-code + nil, // pick some predefined gas price. + common.FromHex("0xd0e30db0")) // Refer to Node.DepositFuncSignature if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, s.accountKey); err == nil { ts := types.Transactions{signedTx} diff --git a/cmd/harmony.go b/cmd/harmony.go index a7f197e30..7aba88723 100644 --- a/cmd/harmony.go +++ b/cmd/harmony.go @@ -143,7 +143,7 @@ func main() { var clientPeer *p2p.Peer var role string - stakingPriKey := utils.LoadStakingKeyFromFile(*stakingKeyFile) + stakingPriKey := node.LoadStakingKeyFromFile(*stakingKeyFile) nodePriKey, _, err := utils.LoadKeyFromFile(*keyFile) if err != nil { @@ -180,8 +180,6 @@ func main() { panic("unable to new host in harmony") } - log.Info("New Harmony Node...", "multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, host.GetID().Pretty())) - host.AddPeer(&leader) // Consensus object. @@ -245,6 +243,7 @@ func main() { } // Assign closure functions to the consensus object + consensus.BlockVerifier = currentNode.VerifyNewBlock consensus.OnConsensusDone = currentNode.PostConsensusProcessing currentNode.State = node.NodeWaitToJoin @@ -252,6 +251,7 @@ func main() { go currentNode.SendPongMessage() } + log.Info("New Harmony Node ====", "Role", currentNode.Role, "multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, host.GetID().Pretty())) go currentNode.SupportSyncing() currentNode.ServiceManagerSetup() currentNode.RunServices() diff --git a/consensus/consensus.go b/consensus/consensus.go index fae1fd17c..21fbc97ab 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -91,6 +91,8 @@ type Consensus struct { // The post-consensus processing func passed from Node object // Called when consensus on a new block is done OnConsensusDone func(*types.Block) + // The verifier func passed from Node object + BlockVerifier func(*types.Block) bool // current consensus block to check if out of sync ConsensusBlock chan *BFTBlockInfo diff --git a/consensus/consensus_leader.go b/consensus/consensus_leader.go index 6b9833f9a..a066575d7 100644 --- a/consensus/consensus_leader.go +++ b/consensus/consensus_leader.go @@ -321,7 +321,7 @@ func (consensus *Consensus) processCommitMessage(message *msg_pb.Message) { consensus.consensusID++ consensus.OnConsensusDone(&blockObj) - utils.GetLogInstance().Debug("HOORAY!!! CONSENSUS REACHED!!!", "consensusID", consensus.consensusID, "numOfSignatures", len(commitSigs)) + utils.GetLogInstance().Debug("HOORAY!!!!!!! CONSENSUS REACHED!!!!!!!", "consensusID", consensus.consensusID, "numOfSignatures", len(commitSigs)) // TODO: remove this temporary delay time.Sleep(500 * time.Millisecond) diff --git a/consensus/consensus_validator.go b/consensus/consensus_validator.go index 81520daee..a600c8305 100644 --- a/consensus/consensus_validator.go +++ b/consensus/consensus_validator.go @@ -262,8 +262,7 @@ func (consensus *Consensus) processCommittedMessage(message *msg_pb.Message) { utils.GetLogInstance().Debug("failed to construct the new block after consensus") } // check block data (transactions - // TODO: change to verify the block body - if err := consensus.VerifyHeader(consensus.ChainReader, blockObj.Header(), true); err != nil { + if err := consensus.VerifyHeader(consensus.ChainReader, blockObj.Header(), false); err != nil { utils.GetLogInstance().Debug("[WARNING] Block content is not verified successfully", "consensusID", consensus.consensusID) return } diff --git a/contracts/DepositContract.sol b/contracts/DepositContract.sol index 5ded4002d..88a34adf0 100644 --- a/contracts/DepositContract.sol +++ b/contracts/DepositContract.sol @@ -24,4 +24,4 @@ contract DepositContract { function stakesBalance() public view returns (uint) { return address(this).balance; } -} \ No newline at end of file +} diff --git a/contracts/Faucet.sol b/contracts/Faucet.sol index 18d52a4fe..5baaf7efa 100644 --- a/contracts/Faucet.sol +++ b/contracts/Faucet.sol @@ -1,7 +1,7 @@ pragma solidity >=0.4.22 <0.6.0; contract Faucet { mapping(address => bool) processed; - uint quota = 0.5 ether; + uint quota = 10 ether; address owner; constructor() public payable { owner = msg.sender; diff --git a/internal/utils/contract/constants.go b/internal/utils/contract/constants.go index 097bc2512..f9de9a692 100644 --- a/internal/utils/contract/constants.go +++ b/internal/utils/contract/constants.go @@ -2,10 +2,11 @@ package contract import ( "crypto/ecdsa" - "fmt" "os" "strings" + "github.com/harmony-one/harmony/internal/utils" + "github.com/ethereum/go-ethereum/crypto" ) @@ -22,7 +23,7 @@ type DeployAccount struct { func BeaconAccountPriKey() *ecdsa.PrivateKey { prikey, err := ecdsa.GenerateKey(crypto.S256(), strings.NewReader(beaconGenesisString)) if err != nil && prikey == nil { - fmt.Println("MINHDOAN***", err) + utils.GetLogInstance().Error("Failed to generate beacon chain contract deployer account") os.Exit(1) } return prikey @@ -37,6 +38,16 @@ var GenesisBeaconAccountPublicKey = GenesisBeaconAccountPriKey.PublicKey // DeployedContractAddress is the deployed contract address of the staking smart contract in beacon chain. var DeployedContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(GenesisBeaconAccountPublicKey), uint64(0)) +// StakingAccounts is the accounts only used for staking. +var StakingAccounts = [...]DeployAccount{ + {Address: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84", Private: "e401343197a852f361e38ce6b46c99f1d6d1f80499864c6ae7effee42b46ab6b", Public: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84"}, + {Address: "0x183418934Fd8A97c98E086151317B2df6259b8A8", Private: "a7d764439a7619f703c97ee2a2cf0be2cd62ad4c9deebd5423d6f28de417b907", Public: "0x183418934Fd8A97c98E086151317B2df6259b8A8"}, + {Address: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6", Private: "4e3f7c819a15249d2824834cd7ce20fe24d6eab8eb39ac63b78cb3713362cf78", Public: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6"}, + {Address: "0x64570B8D2f9028b850340b6710bB0027baC5EFa2", Private: "8565eded3f70b2f8608495fa7e301fefc36cbc03286c0f4e75ffde7e02b49791", Public: "0x64570B8D2f9028b850340b6710bB0027baC5EFa2"}, + {Address: "0x7E653426a7E0c1D210A652bf0E74B15838059b80", Private: "23176da901759e231d7b2d8761f3448220fcfd0232ed0b9644689a6ad7d50990", Public: "0x7E653426a7E0c1D210A652bf0E74B15838059b80"}, + {Address: "0xAe44500A96756112C69F88008388037F6C6dd723", Private: "a9b4c273ffa398a1b1c8eeab63c40cef2c2fb2fc1fc4de9ab73a61f12e4d990a", Public: "0xAe44500A96756112C69F88008388037F6C6dd723"}, +} + // FakeAccounts is the accounts only used for development purpose. var FakeAccounts = [...]DeployAccount{ {Address: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84", Private: "e401343197a852f361e38ce6b46c99f1d6d1f80499864c6ae7effee42b46ab6b", Public: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84"}, diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 4f8aa7a80..73fc96c71 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -2,7 +2,6 @@ package utils import ( "bytes" - "crypto/ecdsa" "encoding/binary" "encoding/json" "fmt" @@ -14,7 +13,6 @@ import ( "strconv" "sync" - crypto "github.com/ethereum/go-ethereum/crypto" "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/p2p" p2p_crypto "github.com/libp2p/go-libp2p-crypto" @@ -216,23 +214,3 @@ func LoadKeyFromFile(keyfile string) (key p2p_crypto.PrivKey, pk p2p_crypto.PubK key, pk, err = LoadPrivateKey(keyStruct.Key) return key, pk, err } - -// LoadStakingKeyFromFile load staking private key from keyfile -// If the private key is not loadable or no file, it will generate -// a new random private key -func LoadStakingKeyFromFile(keyfile string) *ecdsa.PrivateKey { - key, err := crypto.LoadECDSA(keyfile) - if err != nil { - GetLogInstance().Error("no key file. Let's create a staking private key") - key, err = crypto.GenerateKey() - if err != nil { - GetLogInstance().Error("Unable to generate the private key") - os.Exit(1) - } - if err = crypto.SaveECDSA(keyfile, key); err != nil { - GetLogInstance().Error("Unable to save the private key", "error", err) - os.Exit(1) - } - } - return key -} diff --git a/node/contract.go b/node/contract.go index 6f45c4250..505660d93 100644 --- a/node/contract.go +++ b/node/contract.go @@ -6,6 +6,8 @@ import ( "math/big" "strings" + "github.com/harmony-one/harmony/internal/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -37,7 +39,7 @@ func (node *Node) AddStakingContractToPendingTransactions() { // Unsigned transaction to avoid the case of transaction address. mycontracttx, _ := types.SignTx(types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, priKey) //node.StakingContractAddress = crypto.CreateAddress(contractAddress, uint64(0)) - node.StakingContractAddress = node.generateDeployedStakingContractAddress(mycontracttx, contractAddress) + node.StakingContractAddress = node.generateDeployedStakingContractAddress(contractAddress) node.addPendingTransactions(types.Transactions{mycontracttx}) } @@ -45,9 +47,7 @@ func (node *Node) AddStakingContractToPendingTransactions() { // (Refer: https://solidity.readthedocs.io/en/v0.5.3/introduction-to-smart-contracts.html#index-8) // Then we can (re)create the deployed address. Trivially, this is 0 for us. // The deployed contract address can also be obtained via the receipt of the contract creating transaction. -func (node *Node) generateDeployedStakingContractAddress(mycontracttx *types.Transaction, contractAddress common.Address) common.Address { - //Ideally we send the transaction to - +func (node *Node) generateDeployedStakingContractAddress(contractAddress common.Address) common.Address { //Correct Way 1: //node.SendTx(mycontracttx) //receipts := node.worker.GetCurrentReceipts() @@ -56,7 +56,6 @@ func (node *Node) generateDeployedStakingContractAddress(mycontracttx *types.Tra //Correct Way 2: //nonce := GetNonce(contractAddress) //deployedAddress := crypto.CreateAddress(contractAddress, uint64(nonce)) - //deployedcontractaddress = recepits[len(receipts)-1].ContractAddress //get the address from the receipt nonce := 0 return crypto.CreateAddress(contractAddress, uint64(nonce)) } @@ -97,7 +96,7 @@ func (node *Node) getDeployedStakingContract() common.Address { // AddFaucetContractToPendingTransactions adds the faucet contract the genesis block. func (node *Node) AddFaucetContractToPendingTransactions() { // Add a contract deployment transactionv - priKey := node.ContractKeys[0] + priKey := node.ContractDeployerKey dataEnc := common.FromHex(FaucetContractBinary) // Unsigned transaction to avoid the case of transaction address. @@ -112,28 +111,38 @@ func (node *Node) AddFaucetContractToPendingTransactions() { } // CallFaucetContract invokes the faucet contract to give the walletAddress initial money -func (node *Node) CallFaucetContract(walletAddress common.Address) common.Hash { - return node.createSendingMoneyTransaction(walletAddress) +func (node *Node) CallFaucetContract(address common.Address) common.Hash { + return node.callGetFreeToken(address) } -func (node *Node) createSendingMoneyTransaction(walletAddress common.Address) common.Hash { +func (node *Node) callGetFreeToken(address common.Address) common.Hash { state, err := node.blockchain.State() if err != nil { log.Error("Failed to get chain state", "Error", err) } - nonce := state.GetNonce(crypto.PubkeyToAddress(node.ContractKeys[0].PublicKey)) - contractData := FaucetFreeMoneyMethodCall + hex.EncodeToString(walletAddress.Bytes()) + nonce := state.GetNonce(crypto.PubkeyToAddress(node.ContractDeployerKey.PublicKey)) + return node.callGetFreeTokenWithNonce(address, nonce) +} + +func (node *Node) callGetFreeTokenWithNonce(address common.Address, nonce uint64) common.Hash { + contractData := FaucetFreeMoneyMethodCall + hex.EncodeToString(address.Bytes()) dataEnc := common.FromHex(contractData) - tx, _ := types.SignTx(types.NewTransaction(nonce, node.ContractAddresses[0], node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.ContractKeys[0]) + utils.GetLogInstance().Info("Sending Free Token to ", "Address", address.Hex()) + tx, _ := types.SignTx(types.NewTransaction(nonce, node.ContractAddresses[0], node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.ContractDeployerKey) node.addPendingTransactions(types.Transactions{tx}) return tx.Hash() } -// DepositToFakeAccounts invokes the faucet contract to give the walletAddress initial money -func (node *Node) DepositToFakeAccounts() { - for _, deployAccount := range contract.FakeAccounts { +// DepositToStakingAccounts invokes the faucet contract to give the staking accounts initial money +func (node *Node) DepositToStakingAccounts() { + state, err := node.blockchain.State() + if err != nil { + log.Error("Failed to get chain state", "Error", err) + } + nonce := state.GetNonce(crypto.PubkeyToAddress(node.ContractDeployerKey.PublicKey)) + 1 // + 1 because deployer key is already used for faucet contract deployment + for i, deployAccount := range contract.StakingAccounts { address := common.HexToAddress(deployAccount.Address) - node.createSendingMoneyTransaction(address) + node.callGetFreeTokenWithNonce(address, nonce+uint64(i)) } } diff --git a/node/node.go b/node/node.go index c36a03a8b..7694559d6 100644 --- a/node/node.go +++ b/node/node.go @@ -58,6 +58,26 @@ const ( ClientNode ) +func (role Role) String() string { + switch role { + case Unknown: + return "Unknown" + case ShardLeader: + return "ShardLeader" + case ShardValidator: + return "ShardValidator" + case BeaconLeader: + return "BeaconLeader" + case BeaconValidator: + return "BeaconValidator" + case NewNode: + return "NewNode" + case ClientNode: + return "ClientNode" + } + return "Unknown" +} + func (state State) String() string { switch state { case NodeInit: @@ -160,9 +180,9 @@ type Node struct { Address common.Address // For test only - TestBankKeys []*ecdsa.PrivateKey - ContractKeys []*ecdsa.PrivateKey - ContractAddresses []common.Address + TestBankKeys []*ecdsa.PrivateKey + ContractDeployerKey *ecdsa.PrivateKey + ContractAddresses []common.Address // Group Message Receiver groupReceiver p2p.GroupReceiver @@ -205,11 +225,9 @@ func (node *Node) addPendingTransactions(newTxs types.Transactions) { func (node *Node) getTransactionsForNewBlock(maxNumTxs int) types.Transactions { node.pendingTxMutex.Lock() selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, maxNumTxs) - _ = invalid // invalid txs are discard - utils.GetLogInstance().Debug("Invalid transactions discarded", "number", len(invalid)) node.pendingTransactions = unselected - utils.GetLogInstance().Debug("Remaining pending transactions", "number", len(node.pendingTransactions), "selected", len(selected)) + utils.GetLogInstance().Debug("Selecting Transactions", "remainPending", len(node.pendingTransactions), "selected", len(selected), "invalidDiscarded", len(invalid)) node.pendingTxMutex.Unlock() return selected } @@ -260,12 +278,16 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database) *N node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, params.TestChainConfig, chain) node.Worker = worker.New(params.TestChainConfig, chain, node.Consensus, pki.GetAddressFromPublicKey(node.SelfPeer.PubKey), node.Consensus.ShardID) - if node.Role == BeaconLeader || node.Role == BeaconValidator { - node.CurrentStakes = make(map[common.Address]int64) - } + utils.GetLogInstance().Debug("Created Genesis Block", "blockHash", chain.GetBlockByNumber(0).Hash().Hex()) node.Consensus.ConsensusBlock = make(chan *consensus.BFTBlockInfo) node.Consensus.VerifiedNewBlock = make(chan *types.Block) + + // Setup one time smart contracts + node.AddFaucetContractToPendingTransactions() + node.CurrentStakes = make(map[common.Address]int64) + node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked + node.DepositToStakingAccounts() } if consensusObj != nil && consensusObj.IsLeader { diff --git a/node/node_genesis.go b/node/node_genesis.go index 6b8979b06..9525024d7 100644 --- a/node/node_genesis.go +++ b/node/node_genesis.go @@ -24,18 +24,12 @@ const ( func (node *Node) GenesisBlockSetup(db ethdb.Database) (*core.BlockChain, error) { // Initialize genesis block and blockchain genesisAlloc := node.CreateGenesisAllocWithTestingAddresses(FakeAddressNumber) - contractKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time")) - contractAddress := crypto.PubkeyToAddress(contractKey.PublicKey) - contractFunds := big.NewInt(TotalInitFund) - contractFunds = contractFunds.Mul(contractFunds, big.NewInt(params.Ether)) - genesisAlloc[contractAddress] = core.GenesisAccount{Balance: contractFunds} - node.ContractKeys = append(node.ContractKeys, contractKey) - - node.AddFaucetContractToPendingTransactions() - if node.Role == BeaconLeader { - node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked - node.DepositToFakeAccounts() - } + contractDeployerKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time")) + contractDeployerAddress := crypto.PubkeyToAddress(contractDeployerKey.PublicKey) + contractDeployerFunds := big.NewInt(TotalInitFund) + contractDeployerFunds = contractDeployerFunds.Mul(contractDeployerFunds, big.NewInt(params.Ether)) + genesisAlloc[contractDeployerAddress] = core.GenesisAccount{Balance: contractDeployerFunds} + node.ContractDeployerKey = contractDeployerKey chainConfig := params.TestChainConfig chainConfig.ChainID = big.NewInt(int64(node.Consensus.ShardID)) // Use ChainID as piggybacked ShardID diff --git a/node/node_handler.go b/node/node_handler.go index 5cad6c183..bc889cf52 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -134,7 +134,7 @@ func (node *Node) messageHandler(content []byte, sender string) { if node.Role != BeaconLeader { return } - node.addStakingTxnIntoPendingTxns(msgPayload) + node.processStakingMessage(msgPayload) case proto.Node: actionType := proto_node.MessageType(msgType) switch actionType { @@ -201,14 +201,14 @@ func (node *Node) messageHandler(content []byte, sender string) { } } -func (node *Node) addStakingTxnIntoPendingTxns(msgPayload []byte) { +func (node *Node) processStakingMessage(msgPayload []byte) { msg := &message.Message{} err := pb.Unmarshal(msgPayload, msg) if err == nil { stakingRequest := msg.GetStaking() txs := types.Transactions{} if err = rlp.DecodeBytes(stakingRequest.Transaction, &txs); err == nil { - utils.GetLogInstance().Error("Successfully added staking transaction to pending list.") + utils.GetLogInstance().Info("Successfully added staking transaction to pending list.") node.addPendingTransactions(txs) } else { utils.GetLogInstance().Error("Failed to unmarshal staking transaction list", "error", err) @@ -286,10 +286,12 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) bool { // 1. add the new block to blockchain // 2. [leader] send new block to the client func (node *Node) PostConsensusProcessing(newBlock *types.Block) { - // if node.Role == BeaconLeader || node.Role == BeaconValidator { - // utils.GetLogInstance().Info("PostConsensusProcessing") - // node.UpdateStakingList(newBlock) - // } + utils.GetLogInstance().Info("PostConsensusProcessing") + if node.Role == BeaconLeader { + utils.GetLogInstance().Info("Updating staking list") + node.UpdateStakingList(newBlock) + node.printStakingList() + } if node.Consensus.IsLeader { node.BroadcastNewBlock(newBlock) } diff --git a/node/node_newblock.go b/node/node_newblock.go index 7bf6fb3ee..e65a612aa 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -47,8 +47,8 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan threshold = FirstTimeThreshold firstTime = false } - utils.GetLogInstance().Debug("Proposing New Block...", "threshold", threshold, "pendingTransactions", len(node.pendingTransactions)) if len(node.pendingTransactions) >= threshold { + utils.GetLogInstance().Debug("PROPOSING NEW BLOCK ------------------------------------------------", "threshold", threshold, "pendingTransactions", len(node.pendingTransactions)) // Normal tx block consensus selectedTxs := node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock) if len(selectedTxs) != 0 { diff --git a/node/service_setup.go b/node/service_setup.go index 7125b0118..c432e31aa 100644 --- a/node/service_setup.go +++ b/node/service_setup.go @@ -3,6 +3,8 @@ package node import ( "os" + "github.com/harmony-one/harmony/api/service/staking" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" msg_pb "github.com/harmony-one/harmony/api/proto/message" @@ -14,7 +16,6 @@ import ( "github.com/harmony-one/harmony/api/service/explorer" "github.com/harmony-one/harmony/api/service/networkinfo" "github.com/harmony-one/harmony/api/service/randomness" - "github.com/harmony-one/harmony/api/service/staking" "github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/node/worker" @@ -80,7 +81,7 @@ func (node *Node) setupForNewNode() { nodeConfig, chanPeer := node.initNodeConfiguration() // Register staking service. - node.serviceManager.RegisterService(service.Staking, staking.New(node.host, node.AccountKey, 0, node.beaconChain)) + node.serviceManager.RegisterService(service.Staking, staking.New(node.host, node.AccountKey, node.beaconChain)) // 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 diff --git a/node/staking.go b/node/staking.go index 780e82906..82781169a 100644 --- a/node/staking.go +++ b/node/staking.go @@ -1,7 +1,14 @@ package node import ( + "crypto/ecdsa" "math/big" + "os" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/harmony-one/harmony/internal/utils/contract" + + "github.com/harmony-one/harmony/internal/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/harmony-one/harmony/core/types" @@ -13,7 +20,8 @@ import ( //Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html const ( - depositFuncSignature = "0xd0e30db0" + // DepositFuncSignature is the func signature for deposit method + DepositFuncSignature = "0xd0e30db0" withdrawFuncSignature = "0x2e1a7d4d" funcSingatureBytes = 4 ) @@ -27,13 +35,14 @@ func (node *Node) UpdateStakingList(block *types.Block) error { txn := txns[i] toAddress := txn.To() if toAddress != nil && *toAddress != node.StakingContractAddress { //Not a address aimed at the staking contract. + utils.GetLogInstance().Info("Mismatched Staking Contract Address", "expected", node.StakingContractAddress.Hex(), "got", toAddress.Hex()) continue } currentSender, _ := types.Sender(signerType, txn) _, isPresent := node.CurrentStakes[currentSender] data := txn.Data() switch funcSignature := decodeFuncSign(data); funcSignature { - case depositFuncSignature: //deposit, currently: 0xd0e30db0 + case DepositFuncSignature: //deposit, currently: 0xd0e30db0 amount := txn.Value() value := amount.Int64() if isPresent { @@ -63,6 +72,16 @@ func (node *Node) UpdateStakingList(block *types.Block) error { return nil } +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) + } + utils.GetLogInstance().Info("CURRENT STAKING INFO [END} ------------------------------------") + utils.GetLogInstance().Info("\n") +} + //The first four bytes of the call data for a function call specifies the function to be called. //It is the first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) //Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html @@ -80,3 +99,36 @@ func decodeFuncSign(data []byte) string { funcSign := hexutil.Encode(data[:funcSingatureBytes]) //The function signature is first 4 bytes of data in ethereum return funcSign } + +// LoadStakingKeyFromFile load staking private key from keyfile +// If the private key is not loadable or no file, it will generate +// a new random private key +// Currently for deploy_newnode.sh, we hard-coded the first fake account as staking account and +// it is minted in genesis block. See genesis_node.go +func LoadStakingKeyFromFile(keyfile string) *ecdsa.PrivateKey { + // contract.FakeAccounts[0] gets minted tokens in genesis block of beacon chain. + key, err := crypto.HexToECDSA(contract.FakeAccounts[0].Private) + if err != nil { + utils.GetLogInstance().Error("Unable to get staking key") + os.Exit(1) + } + if err := crypto.SaveECDSA(keyfile, key); err != nil { + utils.GetLogInstance().Error("Unable to save the private key", "error", err) + os.Exit(1) + } + // TODO(minhdoan): Enable this back. + // key, err := crypto.LoadECDSA(keyfile) + // if err != nil { + // GetLogInstance().Error("no key file. Let's create a staking private key") + // key, err = crypto.GenerateKey() + // if err != nil { + // GetLogInstance().Error("Unable to generate the private key") + // os.Exit(1) + // } + // if err = crypto.SaveECDSA(keyfile, key); err != nil { + // GetLogInstance().Error("Unable to save the private key", "error", err) + // os.Exit(1) + // } + // } + return key +} diff --git a/test/deploy.sh b/test/deploy.sh index 2c6b68f16..8474dc281 100755 --- a/test/deploy.sh +++ b/test/deploy.sh @@ -130,10 +130,13 @@ $DRYRUN $ROOT/bin/bootnode -port 19876 > $log_folder/bootnode.log 2>&1 | tee -a sleep 1 BN_MA=$(grep "BN_MA" $log_folder/bootnode.log | awk -F\= ' { print $2 } ') HMY_OPT2=" -bootnodes $BN_MA" +echo "bootnode launched." + " $BN_MA" HMY_OPT3=" -is_beacon" NUM_NN=0 +sleep 2 + # Start nodes while IFS='' read -r line || [[ -n "$line" ]]; do IFS=' ' read ip port mode shardID <<< $line diff --git a/test/deploy_newnode.sh b/test/deploy_newnode.sh index c89041532..50e97600a 100755 --- a/test/deploy_newnode.sh +++ b/test/deploy_newnode.sh @@ -115,6 +115,7 @@ mkdir -p $log_folder LOG_FILE=$log_folder/r.log HMY_OPT= +# Change to the beacon chain output from deploy.sh HMY_OPT2= HMY_OPT3=