diff --git a/node/contract.go b/node/contract.go index 86647ee7a..7236a3737 100644 --- a/node/contract.go +++ b/node/contract.go @@ -20,8 +20,7 @@ const ( FaucetContractBinary = "0x6080604052678ac7230489e8000060015560028054600160a060020a031916331790556101aa806100316000396000f3fe608060405260043610610045577c0100000000000000000000000000000000000000000000000000000000600035046327c78c42811461004a5780634ddd108a1461008c575b600080fd5b34801561005657600080fd5b5061008a6004803603602081101561006d57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166100b3565b005b34801561009857600080fd5b506100a1610179565b60408051918252519081900360200190f35b60025473ffffffffffffffffffffffffffffffffffffffff1633146100d757600080fd5b600154303110156100e757600080fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526020819052604090205460ff161561011a57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116600081815260208190526040808220805460ff1916600190811790915554905181156108fc0292818181858888f19350505050158015610175573d6000803e3d6000fd5b5050565b30319056fea165627a7a723058203e799228fee2fa7c5d15e71c04267a0cc2687c5eff3b48b98f21f355e1064ab30029" FaucetContractFund = 8000000 FaucetFreeMoneyMethodCall = "0x27c78c42000000000000000000000000" - - StakingContractBinary = "0x608060405234801561001057600080fd5b50610b51806100206000396000f3fe608060405260043610610072576000357c01000000000000000000000000000000000000000000000000000000009004806325ca4c9c146100775780632e1a7d4d146100e05780634c1b64cb1461012f578063a98e4e7714610194578063d0e30db0146101bf578063e27fd057146101dd575b600080fd5b34801561008357600080fd5b506100c66004803603602081101561009a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610249565b604051808215151515815260200191505060405180910390f35b3480156100ec57600080fd5b506101196004803603602081101561010357600080fd5b8101908080359060200190929190505050610310565b6040518082815260200191505060405180910390f35b34801561013b57600080fd5b5061017e6004803603602081101561015257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506104cb565b6040518082815260200191505060405180910390f35b3480156101a057600080fd5b506101a96106f3565b6040518082815260200191505060405180910390f35b6101c7610700565b6040518082815260200191505060405180910390f35b3480156101e957600080fd5b506101f2610a46565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561023557808201518184015260208101905061021a565b505050509050019250505060405180910390f35b6000806002805490501415610261576000905061030b565b8173ffffffffffffffffffffffffffffffffffffffff166002600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548154811015156102c657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161490505b919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548211151561048457816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156103eb573d6000803e3d6000fd5b5060008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561043e5761043c336104cb565b505b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506104c6565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b600080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260016002805490500381548110151561052957fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060028381548110151561056657fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060028054809190600190036106079190610ad4565b508373ffffffffffffffffffffffffffffffffffffffff167e1fab73a76dc2de66330e055b1c1e3319c77b736bb4478cc706497f318a4ad7836040518082815260200191505060405180910390a28073ffffffffffffffffffffffffffffffffffffffff167f6095abd20e12b7e743432b409b7879ac77a0b927f89ae330f59c15b32dce0b69836000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051808381526020018281526020019250505060405180910390a28192505050919050565b6000600280549050905090565b600061070b33610249565b1561087657346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167f6095abd20e12b7e743432b409b7879ac77a0b927f89ae330f59c15b32dce0b69600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051808381526020018281526020019250505060405180910390a2600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050610a43565b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600160023390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555003600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff167fd2ad617bb539c9a6219058035b15d87478e478eb0f74164eae890a0c70fa3f40600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051808381526020018281526020019250505060405180910390a260016002805490500390505b90565b60606002805480602002602001604051908101604052809291908181526020018280548015610aca57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610a80575b5050505050905090565b815481835581811115610afb57818360005260206000209182019101610afa9190610b00565b5b505050565b610b2291905b80821115610b1e576000816000905550600101610b06565b5090565b9056fea165627a7a7230582032eb9f748231d6ef2fd0ac6bd603cc3e381b6a6596e87beb1f6ce117e5237f4b0029" + StakingContractBinary = "0x608060405234801561001057600080fd5b506103f7806100206000396000f3fe608060405260043610610067576000357c01000000000000000000000000000000000000000000000000000000009004806317437a2c1461006c5780632e1a7d4d146100975780638da5cb5b146100e6578063b69ef8a81461013d578063d0e30db014610168575b600080fd5b34801561007857600080fd5b50610081610186565b6040518082815260200191505060405180910390f35b3480156100a357600080fd5b506100d0600480360360208110156100ba57600080fd5b81019080803590602001909291905050506101a5565b6040518082815260200191505060405180910390f35b3480156100f257600080fd5b506100fb6102cd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561014957600080fd5b506101526102f3565b6040518082815260200191505060405180910390f35b610170610339565b6040518082815260200191505060405180910390f35b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115156102c757816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610280573d6000803e3d6000fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506102c8565b5b919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b6000346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509056fea165627a7a723058204acf95662eb95006df1e0b8ba32316211039c7872bc6eb99d12689c1624143d80029" ) // AddStakingContractToPendingTransactions adds the deposit smart contract the genesis block. @@ -51,19 +50,21 @@ func (node *Node) CreateStakingWithdrawTransaction(stake string) (*types.Transac log.Error("Failed to get chain state", "Error", err) } nonce := state.GetNonce(crypto.PubkeyToAddress(DepositContractPriKey.PublicKey)) - //Following: https://github.com/miguelmota/ethereum-development-with-go-book/blob/master/code/transfer_tokens.go - withdrawFnSignature := []byte("withdraw(uint)") + + withdrawFnSignature := []byte("withdraw(uint256)") hash := sha3.NewLegacyKeccak256() hash.Write(withdrawFnSignature) methodID := hash.Sum(nil)[:4] - amount := new(big.Int) - amount.SetString(stake, 10) - paddedAmount := common.LeftPadBytes(amount.Bytes(), 32) + withdraw := stake + withdrawstake := new(big.Int) + withdrawstake.SetString(withdraw, 10) + paddedAmount := common.LeftPadBytes(withdrawstake.Bytes(), 32) var dataEnc []byte dataEnc = append(dataEnc, methodID...) dataEnc = append(dataEnc, paddedAmount...) + tx, err := types.SignTx(types.NewTransaction(nonce, DepositContractAddress, node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey) return tx, err } diff --git a/node/node.go b/node/node.go index 673d80016..ee18e1f96 100644 --- a/node/node.go +++ b/node/node.go @@ -15,6 +15,7 @@ import ( "github.com/harmony-one/harmony/drand" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" @@ -31,6 +32,7 @@ import ( "github.com/harmony-one/harmony/api/service/explorer" "github.com/harmony-one/harmony/api/service/networkinfo" randomness_service "github.com/harmony-one/harmony/api/service/randomness" + "github.com/harmony-one/harmony/api/service/staking" "github.com/harmony-one/harmony/api/service/syncing" "github.com/harmony-one/harmony/api/service/syncing/downloader" @@ -116,6 +118,17 @@ type syncConfig struct { client *downloader.Client } +//constants related to staking +//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 + +const ( + depositFuncSignature = "0xd0e30db0" + withdrawFuncSignature = "0x2e1a7d4d" + funcSingatureBytes = 4 +) + // Node represents a protocol-participating node in the network type Node struct { Consensus *bft.Consensus // Consensus object containing all Consensus related data (e.g. committee members, signatures, commits) @@ -272,6 +285,7 @@ func New(host p2p.Host, consensus *bft.Consensus, db ethdb.Database) *Node { node.blockchain = chain node.BlockChannel = make(chan *types.Block) node.ConfirmedBlockChannel = make(chan *types.Block) + 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) node.AddFaucetContractToPendingTransactions() @@ -632,27 +646,27 @@ func (node *Node) UpdateStakingList(block *types.Block) error { txns := block.Transactions() for i := range txns { txn := txns[i] - value := txn.Value().Int64() - currentSender, _ := types.Sender(signerType, txn) - _, isPresent := node.CurrentStakes[currentSender] toAddress := txn.To() if *toAddress != node.StakingContractAddress { //Not a address aimed at the staking contract. continue } - //This should be based on a switch case on function signature. - //TODO (ak) https://github.com/harmony-one/harmony/issues/430 - if value > int64(0) { //If value >0 means its a staking deposit transaction + currentSender, _ := types.Sender(signerType, txn) + _, isPresent := node.CurrentStakes[currentSender] + data := txn.Data() + switch funcSignature := decodeFuncSign(data); funcSignature { + case depositFuncSignature: //deposit, currently: 0xd0e30db0 + amount := txn.Value() + value := amount.Int64() if isPresent { - //This means this node has increaserd its stake + //This means the node has increased its stake. node.CurrentStakes[currentSender] += value } else { + //This means its a new node that is staking the first time. node.CurrentStakes[currentSender] = value } - } else { //This means node has withdrawn stake. - getData := txn.Data() - value := decodeStakeCall(getData) //Value being withdrawn + case withdrawFuncSignature: //withdaw, currently: 0x2e1a7d4d + value := decodeStakeCall(data) if isPresent { - //This means this node has increaserd its stake if node.CurrentStakes[currentSender] > value { node.CurrentStakes[currentSender] -= value } else if node.CurrentStakes[currentSender] == value { @@ -661,18 +675,33 @@ func (node *Node) UpdateStakingList(block *types.Block) error { continue //Overdraft protection. } } else { - node.CurrentStakes[currentSender] = value + continue //no-op: a node that is not staked cannot withdraw stake. } + default: + continue //no-op if its not deposit or withdaw } } return nil } +//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 func decodeStakeCall(getData []byte) int64 { value := new(big.Int) - value.SetBytes(getData[4:]) //Escape the method call. + value.SetBytes(getData[funcSingatureBytes:]) //Escape the method call. return value.Int64() } + +//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 +//gets the function signature from data. +func decodeFuncSign(data []byte) string { + funcSign := hexutil.Encode(data[:funcSingatureBytes]) //The function signature is first 4 bytes of data in ethereum + return funcSign +} + func (node *Node) setupForShardLeader() { // Register explorer service. node.serviceManager.RegisterService(service_manager.SupportExplorer, explorer.New(&node.SelfPeer)) diff --git a/node/node_test.go b/node/node_test.go index d08348e1a..7356e3fe0 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -243,17 +243,20 @@ func TestUpdateStakingWithdrawal(t *testing.T) { node.StakingContractAddress = DepositContractAddress node.AccountKey, _ = crypto.GenerateKey() Address := crypto.PubkeyToAddress(node.AccountKey.PublicKey) - node.CurrentStakes[Address] = int64(1010) + initialStake := int64(1010) + node.CurrentStakes[Address] = initialStake //initial stake - withdrawFnSignature := []byte("withdraw(uint)") + withdrawFnSignature := []byte("withdraw(uint256)") hash := sha3.NewLegacyKeccak256() hash.Write(withdrawFnSignature) methodID := hash.Sum(nil)[:4] - stake := "1000" - amount := new(big.Int) - amount.SetString(stake, 10) - paddedAmount := common.LeftPadBytes(amount.Bytes(), 32) + amount := "10" + stakeToWithdraw := new(big.Int) + stakeToWithdraw.SetString(amount, 10) + paddedAmount := common.LeftPadBytes(stakeToWithdraw.Bytes(), 32) + + remainingStakeShouldBe := initialStake - stakeToWithdraw.Int64() var dataEnc []byte dataEnc = append(dataEnc, methodID...) @@ -265,11 +268,11 @@ func TestUpdateStakingWithdrawal(t *testing.T) { header := &types.Header{Extra: []byte("hello")} block := types.NewBlock(header, txs, nil) node.UpdateStakingList(block) - value, ok := node.CurrentStakes[Address] + currentStake, ok := node.CurrentStakes[Address] if !ok { t.Error("The correct address was not present") } - if value != 10 { + if currentStake != remainingStakeShouldBe { t.Error("The correct stake value was not subtracted") }