Merge pull request #535 from harmony-one/rj_branch

Use solc generated abi and update CurrentStake by querying stake contract.
pull/544/head
Rongjian Lan 6 years ago committed by GitHub
commit 502e47ba2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      api/service/staking/service.go
  2. 9
      contracts/README.md
  3. 620
      contracts/StakeLockContract.go
  4. 143
      contracts/StakeLockContract.json
  5. 4
      contracts/StakeLockContract.sol
  6. 60
      contracts/contract_caller.go
  7. 2
      go.mod
  8. 7
      go.sum
  9. 59
      node/contract.go
  10. 12
      node/node.go
  11. 11
      node/node_handler.go
  12. 73
      node/staking.go
  13. 105
      node/staking_test.go
  14. 5
      scripts/install_solc.sh
  15. BIN
      test/crypto/bls/main

@ -3,10 +3,11 @@ package staking
import (
"crypto/ecdsa"
"math/big"
"os"
"strings"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/harmony-one/harmony/contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -101,13 +102,6 @@ func (s *Service) IsStaked() bool {
// DoService does staking.
func (s *Service) DoService() {
utils.GetLogInstance().Info("Trying to send a staking transaction.")
abi, err := s.getStakeLockContractABI()
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
} else {
utils.GetLogInstance().Info("Generated staking contract's ABI", "abi", abi)
}
// TODO: use abi to generate staking transaction.
if s.beaconChain == nil {
utils.GetLogInstance().Info("Can not send a staking transaction because of nil beacon chain.")
@ -121,17 +115,6 @@ func (s *Service) DoService() {
}
}
func (s *Service) getStakeLockContractABI() (abi.ABI, error) {
f, err := os.Open("./contracts/StakeLockContract.json")
if err != nil {
if os.IsNotExist(err) {
return abi.ABI{}, err
}
}
defer f.Close()
return abi.JSON(f)
}
func (s *Service) getStakingInfo() *proto.StakingContractInfoResponse {
address := crypto.PubkeyToAddress(s.accountKey.PublicKey)
state, err := s.beaconChain.State()
@ -196,6 +179,16 @@ func (s *Service) createRawStakingMessage() []byte {
// TODO(minhdoan): Enable getStakingInfo back after testing.
stakingInfo := s.getFakeStakingInfo()
toAddress := common.HexToAddress(stakingInfo.ContractAddress)
abi, err := abi.JSON(strings.NewReader(contracts.StakeLockContractABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
}
bytesData, err := abi.Pack("lock")
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
}
tx := types.NewTransaction(
stakingInfo.Nonce,
toAddress,
@ -203,7 +196,7 @@ func (s *Service) createRawStakingMessage() []byte {
big.NewInt(s.stakingAmount),
params.TxGas*10,
nil,
common.FromHex("0xd0e30db0"),
bytesData,
)
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, s.accountKey); err == nil {

@ -2,3 +2,12 @@ The smart contract files in this folder contains protocol-level smart contracts
* Faucet.sol is the smart contract to dispense free test tokens in our testnet.
* StakeLockContract.sol is the staking smart contract that receives and locks stakes. The stakes are used for the POS and sharding protocol.
Solc is needed to recompile the contracts into ABI and bytecode. Please follow https://solidity.readthedocs.io/en/v0.5.3/installing-solidity.html for the installation.
Example command to compile a contract file into golang ABI.
```bash
abigen -sol contracts/StakeLockContract.sol -pkg contracts -out contracts/StakeLockContract.go
```

@ -0,0 +1,620 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package contracts
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
)
// StakeLockContractABI is the input ABI used to generate the binding from.
const StakeLockContractABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"listLockedAddresses\",\"outputs\":[{\"name\":\"lockedAddresses\",\"type\":\"address[]\"},{\"name\":\"blockNums\",\"type\":\"uint256[]\"},{\"name\":\"lockPeriodCounts\",\"type\":\"uint256[]\"},{\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_of\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"unlock\",\"outputs\":[{\"name\":\"unlockableTokens\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_of\",\"type\":\"address\"}],\"name\":\"getUnlockableTokens\",\"outputs\":[{\"name\":\"unlockableTokens\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"lock\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_of\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"_epoch\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"Unlocked\",\"type\":\"event\"}]"
// StakeLockContractBin is the compiled bytecode used for deploying new contracts.
const StakeLockContractBin = `0x6080604052600560005534801561001557600080fd5b5061095a806100256000396000f3fe6080604052600436106100555760003560e01c806363b125151461005a57806370a082311461019257806376671808146101d7578063a69df4b5146101ec578063ab4a2eb314610201578063f83d08ba14610234575b600080fd5b34801561006657600080fd5b5061006f610250565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b838110156100bb5781810151838201526020016100a3565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156100fa5781810151838201526020016100e2565b50505050905001858103835287818151815260200191508051906020019060200280838360005b83811015610139578181015183820152602001610121565b50505050905001858103825286818151815260200191508051906020019060200280838360005b83811015610178578181015183820152602001610160565b505050509050019850505050505050505060405180910390f35b34801561019e57600080fd5b506101c5600480360360208110156101b557600080fd5b50356001600160a01b031661045f565b60408051918252519081900360200190f35b3480156101e357600080fd5b506101c561047a565b3480156101f857600080fd5b506101c561048f565b34801561020d57600080fd5b506101c56004803603602081101561022457600080fd5b50356001600160a01b031661067c565b61023c6106d9565b604080519115158252519081900360200190f35b60608060608060038054806020026020016040519081016040528092919081815260200182805480156102ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161028e575b505050505093506003805490506040519080825280602002602001820160405280156102e2578160200160208202803883390190505b506003546040805182815260208084028201019091529194508015610311578160200160208202803883390190505b506003546040805182815260208084028201019091529193508015610340578160200160208202803883390190505b50905060005b84518110156104585760016000868381518110151561036157fe5b906020019060200201516001600160a01b03166001600160a01b0316815260200190815260200160002060010154848281518110151561039d57fe5b6020908102909101015284516001906000908790849081106103bb57fe5b906020019060200201516001600160a01b03166001600160a01b031681526020019081526020016000206003015483828151811015156103f757fe5b60209081029091010152845160019060009087908490811061041557fe5b60209081029091018101516001600160a01b0316825281019190915260400160002054825183908390811061044657fe5b60209081029091010152600101610346565b5090919293565b6001600160a01b031660009081526001602052604090205490565b600080544381151561048857fe5b0490505b90565b600061049a3361067c565b60408051808201909152601481527f4e6f20746f6b656e7320756e6c6f636b61626c65000000000000000000000000602082015290915081151561055f57604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561052457818101518382015260200161050c565b50505050905090810190601f1680156105515780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50336000908152600160208190526040822060048101805484835592820184905560028201849055600391820184905592909255815490919060001981019081106105a657fe5b600091825260209091200154600380546001600160a01b0390921691839081106105cc57fe5b6000918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091556003805483926001929091600019810190811061060e57fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190206004015560038054906106499060001983016108e7565b50604051339083156108fc029084906000818181858888f19350505050158015610677573d6000803e3d6000fd5b505090565b60008061068761047a565b6001600160a01b038416600090815260016020526040902060038181015460029092015492935002018111156106d3576001600160a01b03831660009081526001602052604090205491505b50919050565b60006106e43361045f565b60408051808201909152601581527f546f6b656e7320616c7265616479206c6f636b656400000000000000000000006020820152901561076957604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561052457818101518382015260200161050c565b5060408051808201909152601381527f416d6f756e742063616e206e6f7420626520300000000000000000000000000060208201523415156107f057604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561052457818101518382015260200161050c565b506040518060a0016040528034815260200143815260200161081061047a565b8152600160208083018290526003805480840182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810180546001600160a01b0319163390811790915560409586019190915260008181528484528590208651815592860151938301939093559284015160028201556060840151928101929092556080909201516004909101557fd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5346108c961047a565b6040805192835260208301919091528051918290030190a250600190565b81548183558181111561090b5760008381526020902061090b918101908301610910565b505050565b61048c91905b8082111561092a5760008155600101610916565b509056fea165627a7a723058209f27dc5388d4508d0aeccbbf0ae74929289525f4918465e7eee508195182385c0029`
// DeployStakeLockContract deploys a new Ethereum contract, binding an instance of StakeLockContract to it.
func DeployStakeLockContract(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *StakeLockContract, error) {
parsed, err := abi.JSON(strings.NewReader(StakeLockContractABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(StakeLockContractBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &StakeLockContract{StakeLockContractCaller: StakeLockContractCaller{contract: contract}, StakeLockContractTransactor: StakeLockContractTransactor{contract: contract}, StakeLockContractFilterer: StakeLockContractFilterer{contract: contract}}, nil
}
// StakeLockContract is an auto generated Go binding around an Ethereum contract.
type StakeLockContract struct {
StakeLockContractCaller // Read-only binding to the contract
StakeLockContractTransactor // Write-only binding to the contract
StakeLockContractFilterer // Log filterer for contract events
}
// StakeLockContractCaller is an auto generated read-only Go binding around an Ethereum contract.
type StakeLockContractCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// StakeLockContractTransactor is an auto generated write-only Go binding around an Ethereum contract.
type StakeLockContractTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// StakeLockContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type StakeLockContractFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// StakeLockContractSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type StakeLockContractSession struct {
Contract *StakeLockContract // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// StakeLockContractCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type StakeLockContractCallerSession struct {
Contract *StakeLockContractCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// StakeLockContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type StakeLockContractTransactorSession struct {
Contract *StakeLockContractTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// StakeLockContractRaw is an auto generated low-level Go binding around an Ethereum contract.
type StakeLockContractRaw struct {
Contract *StakeLockContract // Generic contract binding to access the raw methods on
}
// StakeLockContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type StakeLockContractCallerRaw struct {
Contract *StakeLockContractCaller // Generic read-only contract binding to access the raw methods on
}
// StakeLockContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type StakeLockContractTransactorRaw struct {
Contract *StakeLockContractTransactor // Generic write-only contract binding to access the raw methods on
}
// NewStakeLockContract creates a new instance of StakeLockContract, bound to a specific deployed contract.
func NewStakeLockContract(address common.Address, backend bind.ContractBackend) (*StakeLockContract, error) {
contract, err := bindStakeLockContract(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &StakeLockContract{StakeLockContractCaller: StakeLockContractCaller{contract: contract}, StakeLockContractTransactor: StakeLockContractTransactor{contract: contract}, StakeLockContractFilterer: StakeLockContractFilterer{contract: contract}}, nil
}
// NewStakeLockContractCaller creates a new read-only instance of StakeLockContract, bound to a specific deployed contract.
func NewStakeLockContractCaller(address common.Address, caller bind.ContractCaller) (*StakeLockContractCaller, error) {
contract, err := bindStakeLockContract(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &StakeLockContractCaller{contract: contract}, nil
}
// NewStakeLockContractTransactor creates a new write-only instance of StakeLockContract, bound to a specific deployed contract.
func NewStakeLockContractTransactor(address common.Address, transactor bind.ContractTransactor) (*StakeLockContractTransactor, error) {
contract, err := bindStakeLockContract(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &StakeLockContractTransactor{contract: contract}, nil
}
// NewStakeLockContractFilterer creates a new log filterer instance of StakeLockContract, bound to a specific deployed contract.
func NewStakeLockContractFilterer(address common.Address, filterer bind.ContractFilterer) (*StakeLockContractFilterer, error) {
contract, err := bindStakeLockContract(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &StakeLockContractFilterer{contract: contract}, nil
}
// bindStakeLockContract binds a generic wrapper to an already deployed contract.
func bindStakeLockContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(StakeLockContractABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_StakeLockContract *StakeLockContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _StakeLockContract.Contract.StakeLockContractCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_StakeLockContract *StakeLockContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _StakeLockContract.Contract.StakeLockContractTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_StakeLockContract *StakeLockContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _StakeLockContract.Contract.StakeLockContractTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_StakeLockContract *StakeLockContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _StakeLockContract.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_StakeLockContract *StakeLockContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _StakeLockContract.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_StakeLockContract *StakeLockContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _StakeLockContract.Contract.contract.Transact(opts, method, params...)
}
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
//
// Solidity: function balanceOf(address _of) constant returns(uint256 balance)
func (_StakeLockContract *StakeLockContractCaller) BalanceOf(opts *bind.CallOpts, _of common.Address) (*big.Int, error) {
var (
ret0 = new(*big.Int)
)
out := ret0
err := _StakeLockContract.contract.Call(opts, out, "balanceOf", _of)
return *ret0, err
}
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
//
// Solidity: function balanceOf(address _of) constant returns(uint256 balance)
func (_StakeLockContract *StakeLockContractSession) BalanceOf(_of common.Address) (*big.Int, error) {
return _StakeLockContract.Contract.BalanceOf(&_StakeLockContract.CallOpts, _of)
}
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
//
// Solidity: function balanceOf(address _of) constant returns(uint256 balance)
func (_StakeLockContract *StakeLockContractCallerSession) BalanceOf(_of common.Address) (*big.Int, error) {
return _StakeLockContract.Contract.BalanceOf(&_StakeLockContract.CallOpts, _of)
}
// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808.
//
// Solidity: function currentEpoch() constant returns(uint256)
func (_StakeLockContract *StakeLockContractCaller) CurrentEpoch(opts *bind.CallOpts) (*big.Int, error) {
var (
ret0 = new(*big.Int)
)
out := ret0
err := _StakeLockContract.contract.Call(opts, out, "currentEpoch")
return *ret0, err
}
// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808.
//
// Solidity: function currentEpoch() constant returns(uint256)
func (_StakeLockContract *StakeLockContractSession) CurrentEpoch() (*big.Int, error) {
return _StakeLockContract.Contract.CurrentEpoch(&_StakeLockContract.CallOpts)
}
// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808.
//
// Solidity: function currentEpoch() constant returns(uint256)
func (_StakeLockContract *StakeLockContractCallerSession) CurrentEpoch() (*big.Int, error) {
return _StakeLockContract.Contract.CurrentEpoch(&_StakeLockContract.CallOpts)
}
// GetUnlockableTokens is a free data retrieval call binding the contract method 0xab4a2eb3.
//
// Solidity: function getUnlockableTokens(address _of) constant returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractCaller) GetUnlockableTokens(opts *bind.CallOpts, _of common.Address) (*big.Int, error) {
var (
ret0 = new(*big.Int)
)
out := ret0
err := _StakeLockContract.contract.Call(opts, out, "getUnlockableTokens", _of)
return *ret0, err
}
// GetUnlockableTokens is a free data retrieval call binding the contract method 0xab4a2eb3.
//
// Solidity: function getUnlockableTokens(address _of) constant returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractSession) GetUnlockableTokens(_of common.Address) (*big.Int, error) {
return _StakeLockContract.Contract.GetUnlockableTokens(&_StakeLockContract.CallOpts, _of)
}
// GetUnlockableTokens is a free data retrieval call binding the contract method 0xab4a2eb3.
//
// Solidity: function getUnlockableTokens(address _of) constant returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractCallerSession) GetUnlockableTokens(_of common.Address) (*big.Int, error) {
return _StakeLockContract.Contract.GetUnlockableTokens(&_StakeLockContract.CallOpts, _of)
}
// ListLockedAddresses is a free data retrieval call binding the contract method 0x63b12515.
//
// Solidity: function listLockedAddresses() constant returns(address[] lockedAddresses, uint256[] blockNums, uint256[] lockPeriodCounts, uint256[] amounts)
func (_StakeLockContract *StakeLockContractCaller) ListLockedAddresses(opts *bind.CallOpts) (struct {
LockedAddresses []common.Address
BlockNums []*big.Int
LockPeriodCounts []*big.Int
Amounts []*big.Int
}, error) {
ret := new(struct {
LockedAddresses []common.Address
BlockNums []*big.Int
LockPeriodCounts []*big.Int
Amounts []*big.Int
})
out := ret
err := _StakeLockContract.contract.Call(opts, out, "listLockedAddresses")
return *ret, err
}
// ListLockedAddresses is a free data retrieval call binding the contract method 0x63b12515.
//
// Solidity: function listLockedAddresses() constant returns(address[] lockedAddresses, uint256[] blockNums, uint256[] lockPeriodCounts, uint256[] amounts)
func (_StakeLockContract *StakeLockContractSession) ListLockedAddresses() (struct {
LockedAddresses []common.Address
BlockNums []*big.Int
LockPeriodCounts []*big.Int
Amounts []*big.Int
}, error) {
return _StakeLockContract.Contract.ListLockedAddresses(&_StakeLockContract.CallOpts)
}
// ListLockedAddresses is a free data retrieval call binding the contract method 0x63b12515.
//
// Solidity: function listLockedAddresses() constant returns(address[] lockedAddresses, uint256[] blockNums, uint256[] lockPeriodCounts, uint256[] amounts)
func (_StakeLockContract *StakeLockContractCallerSession) ListLockedAddresses() (struct {
LockedAddresses []common.Address
BlockNums []*big.Int
LockPeriodCounts []*big.Int
Amounts []*big.Int
}, error) {
return _StakeLockContract.Contract.ListLockedAddresses(&_StakeLockContract.CallOpts)
}
// Lock is a paid mutator transaction binding the contract method 0xf83d08ba.
//
// Solidity: function lock() returns(bool)
func (_StakeLockContract *StakeLockContractTransactor) Lock(opts *bind.TransactOpts) (*types.Transaction, error) {
return _StakeLockContract.contract.Transact(opts, "lock")
}
// Lock is a paid mutator transaction binding the contract method 0xf83d08ba.
//
// Solidity: function lock() returns(bool)
func (_StakeLockContract *StakeLockContractSession) Lock() (*types.Transaction, error) {
return _StakeLockContract.Contract.Lock(&_StakeLockContract.TransactOpts)
}
// Lock is a paid mutator transaction binding the contract method 0xf83d08ba.
//
// Solidity: function lock() returns(bool)
func (_StakeLockContract *StakeLockContractTransactorSession) Lock() (*types.Transaction, error) {
return _StakeLockContract.Contract.Lock(&_StakeLockContract.TransactOpts)
}
// Unlock is a paid mutator transaction binding the contract method 0xa69df4b5.
//
// Solidity: function unlock() returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractTransactor) Unlock(opts *bind.TransactOpts) (*types.Transaction, error) {
return _StakeLockContract.contract.Transact(opts, "unlock")
}
// Unlock is a paid mutator transaction binding the contract method 0xa69df4b5.
//
// Solidity: function unlock() returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractSession) Unlock() (*types.Transaction, error) {
return _StakeLockContract.Contract.Unlock(&_StakeLockContract.TransactOpts)
}
// Unlock is a paid mutator transaction binding the contract method 0xa69df4b5.
//
// Solidity: function unlock() returns(uint256 unlockableTokens)
func (_StakeLockContract *StakeLockContractTransactorSession) Unlock() (*types.Transaction, error) {
return _StakeLockContract.Contract.Unlock(&_StakeLockContract.TransactOpts)
}
// StakeLockContractLockedIterator is returned from FilterLocked and is used to iterate over the raw logs and unpacked data for Locked events raised by the StakeLockContract contract.
type StakeLockContractLockedIterator struct {
Event *StakeLockContractLocked // Event containing the contract specifics and raw log
contract *bind.BoundContract // Generic contract to use for unpacking event data
event string // Event name to use for unpacking event data
logs chan types.Log // Log channel receiving the found contract events
sub ethereum.Subscription // Subscription for errors, completion and termination
done bool // Whether the subscription completed delivering logs
fail error // Occurred error to stop iteration
}
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *StakeLockContractLockedIterator) Next() bool {
// If the iterator failed, stop iterating
if it.fail != nil {
return false
}
// If the iterator completed, deliver directly whatever's available
if it.done {
select {
case log := <-it.logs:
it.Event = new(StakeLockContractLocked)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
default:
return false
}
}
// Iterator still in progress, wait for either a data or an error event
select {
case log := <-it.logs:
it.Event = new(StakeLockContractLocked)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
case err := <-it.sub.Err():
it.done = true
it.fail = err
return it.Next()
}
}
// Error returns any retrieval or parsing error occurred during filtering.
func (it *StakeLockContractLockedIterator) Error() error {
return it.fail
}
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *StakeLockContractLockedIterator) Close() error {
it.sub.Unsubscribe()
return nil
}
// StakeLockContractLocked represents a Locked event raised by the StakeLockContract contract.
type StakeLockContractLocked struct {
Of common.Address
Amount *big.Int
Epoch *big.Int
Raw types.Log // Blockchain specific contextual infos
}
// FilterLocked is a free log retrieval operation binding the contract event 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5.
//
// Solidity: event Locked(address indexed _of, uint256 _amount, uint256 _epoch)
func (_StakeLockContract *StakeLockContractFilterer) FilterLocked(opts *bind.FilterOpts, _of []common.Address) (*StakeLockContractLockedIterator, error) {
var _ofRule []interface{}
for _, _ofItem := range _of {
_ofRule = append(_ofRule, _ofItem)
}
logs, sub, err := _StakeLockContract.contract.FilterLogs(opts, "Locked", _ofRule)
if err != nil {
return nil, err
}
return &StakeLockContractLockedIterator{contract: _StakeLockContract.contract, event: "Locked", logs: logs, sub: sub}, nil
}
// WatchLocked is a free log subscription operation binding the contract event 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5.
//
// Solidity: event Locked(address indexed _of, uint256 _amount, uint256 _epoch)
func (_StakeLockContract *StakeLockContractFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *StakeLockContractLocked, _of []common.Address) (event.Subscription, error) {
var _ofRule []interface{}
for _, _ofItem := range _of {
_ofRule = append(_ofRule, _ofItem)
}
logs, sub, err := _StakeLockContract.contract.WatchLogs(opts, "Locked", _ofRule)
if err != nil {
return nil, err
}
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case log := <-logs:
// New log arrived, parse the event and forward to the user
event := new(StakeLockContractLocked)
if err := _StakeLockContract.contract.UnpackLog(event, "Locked", log); err != nil {
return err
}
event.Raw = log
select {
case sink <- event:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// StakeLockContractUnlockedIterator is returned from FilterUnlocked and is used to iterate over the raw logs and unpacked data for Unlocked events raised by the StakeLockContract contract.
type StakeLockContractUnlockedIterator struct {
Event *StakeLockContractUnlocked // Event containing the contract specifics and raw log
contract *bind.BoundContract // Generic contract to use for unpacking event data
event string // Event name to use for unpacking event data
logs chan types.Log // Log channel receiving the found contract events
sub ethereum.Subscription // Subscription for errors, completion and termination
done bool // Whether the subscription completed delivering logs
fail error // Occurred error to stop iteration
}
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *StakeLockContractUnlockedIterator) Next() bool {
// If the iterator failed, stop iterating
if it.fail != nil {
return false
}
// If the iterator completed, deliver directly whatever's available
if it.done {
select {
case log := <-it.logs:
it.Event = new(StakeLockContractUnlocked)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
default:
return false
}
}
// Iterator still in progress, wait for either a data or an error event
select {
case log := <-it.logs:
it.Event = new(StakeLockContractUnlocked)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
case err := <-it.sub.Err():
it.done = true
it.fail = err
return it.Next()
}
}
// Error returns any retrieval or parsing error occurred during filtering.
func (it *StakeLockContractUnlockedIterator) Error() error {
return it.fail
}
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *StakeLockContractUnlockedIterator) Close() error {
it.sub.Unsubscribe()
return nil
}
// StakeLockContractUnlocked represents a Unlocked event raised by the StakeLockContract contract.
type StakeLockContractUnlocked struct {
Account common.Address
Index *big.Int
Raw types.Log // Blockchain specific contextual infos
}
// FilterUnlocked is a free log retrieval operation binding the contract event 0x0f0bc5b519ddefdd8e5f9e6423433aa2b869738de2ae34d58ebc796fc749fa0d.
//
// Solidity: event Unlocked(address indexed account, uint256 index)
func (_StakeLockContract *StakeLockContractFilterer) FilterUnlocked(opts *bind.FilterOpts, account []common.Address) (*StakeLockContractUnlockedIterator, error) {
var accountRule []interface{}
for _, accountItem := range account {
accountRule = append(accountRule, accountItem)
}
logs, sub, err := _StakeLockContract.contract.FilterLogs(opts, "Unlocked", accountRule)
if err != nil {
return nil, err
}
return &StakeLockContractUnlockedIterator{contract: _StakeLockContract.contract, event: "Unlocked", logs: logs, sub: sub}, nil
}
// WatchUnlocked is a free log subscription operation binding the contract event 0x0f0bc5b519ddefdd8e5f9e6423433aa2b869738de2ae34d58ebc796fc749fa0d.
//
// Solidity: event Unlocked(address indexed account, uint256 index)
func (_StakeLockContract *StakeLockContractFilterer) WatchUnlocked(opts *bind.WatchOpts, sink chan<- *StakeLockContractUnlocked, account []common.Address) (event.Subscription, error) {
var accountRule []interface{}
for _, accountItem := range account {
accountRule = append(accountRule, accountItem)
}
logs, sub, err := _StakeLockContract.contract.WatchLogs(opts, "Unlocked", accountRule)
if err != nil {
return nil, err
}
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case log := <-logs:
// New log arrived, parse the event and forward to the user
event := new(StakeLockContractUnlocked)
if err := _StakeLockContract.contract.UnpackLog(event, "Unlocked", log); err != nil {
return err
}
event.Raw = log
select {
case sink <- event:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}

@ -1,143 +0,0 @@
[
{
"constant": true,
"inputs": [],
"name": "listLockedAddresses",
"outputs": [
{
"name": "lockedAddresses",
"type": "address[]"
},
{
"name": "blockNums",
"type": "uint256[]"
},
{
"name": "lockPeriodCounts",
"type": "uint256[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_of",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "currentEpoch",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "unlock",
"outputs": [
{
"name": "unlockableTokens",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_of",
"type": "address"
}
],
"name": "getUnlockableTokens",
"outputs": [
{
"name": "unlockableTokens",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "lock",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_of",
"type": "address"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
},
{
"indexed": false,
"name": "_epoch",
"type": "uint256"
}
],
"name": "Locked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "account",
"type": "address"
},
{
"indexed": false,
"name": "index",
"type": "uint256"
}
],
"name": "Unlocked",
"type": "event"
}
]

@ -118,14 +118,16 @@ contract StakeLockContract {
function listLockedAddresses()
public
view
returns (address[] memory lockedAddresses, uint256[] memory blockNums, uint256[] memory lockPeriodCounts)
returns (address[] memory lockedAddresses, uint256[] memory blockNums, uint256[] memory lockPeriodCounts, uint256[] memory amounts)
{
lockedAddresses = addressList;
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;
lockPeriodCounts[i] = locked[lockedAddresses[i]]._lockPeriodCount;
amounts[i] = locked[lockedAddresses[i]]._amount;
}
}
}

@ -0,0 +1,60 @@
package contracts
import (
"sync"
"github.com/harmony-one/harmony/internal/utils"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
)
// ContractCaller is used to call smart contract locally
type ContractCaller struct {
database *ethdb.Database
blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
mu sync.Mutex
config *params.ChainConfig
}
// NewContractCaller initialize a new contract caller.
func NewContractCaller(db *ethdb.Database, bc *core.BlockChain, config *params.ChainConfig) *ContractCaller {
cc := ContractCaller{}
cc.database = db
cc.blockchain = bc
cc.mu = sync.Mutex{}
cc.config = config
return &cc
}
// CallContract calls a contracts with the specified transaction.
func (cc *ContractCaller) CallContract(tx *types.Transaction) ([]byte, error) {
currBlock := cc.blockchain.CurrentBlock()
msg, err := tx.AsMessage(types.MakeSigner(cc.config, currBlock.Header().Number))
if err != nil {
utils.GetLogInstance().Error("[ABI] Failed to convert transaction to message", "error", err)
return []byte{}, err
}
evmContext := core.NewEVMContext(msg, currBlock.Header(), cc.blockchain, nil)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
stateDB, err := cc.blockchain.State()
if err != nil {
utils.GetLogInstance().Error("[ABI] Failed to retrieve state db", "error", err)
return []byte{}, err
}
vmenv := vm.NewEVM(evmContext, stateDB, cc.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
returnValue, _, failed, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
if err != nil || failed {
utils.GetLogInstance().Error("[ABI] Failed executing the transaction", "error", err)
return []byte{}, err
}
return returnValue, nil
}

@ -81,6 +81,8 @@ require (
github.com/multiformats/go-multibase v0.3.0 // indirect
github.com/multiformats/go-multihash v1.0.10 // indirect
github.com/multiformats/go-multistream v0.3.9 // indirect
github.com/pborman/uuid v1.2.0 // indirect
github.com/rjeczalik/notify v0.9.2 // indirect
github.com/rs/cors v1.6.0 // indirect
github.com/shirou/gopsutil v2.18.12+incompatible
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect

@ -21,6 +21,7 @@ github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazu
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/dedis/fixbuf v1.0.2/go.mod h1:2syWkaV6ERSAvTkXkD08E6Nrh3Wl8pHMa8F/+HFuAL4=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
@ -45,6 +46,7 @@ github.com/golang/protobuf v1.2.1-0.20181127190454-8d0c54c12466 h1:Kz9p8XEhFbEfi
github.com/golang/protobuf v1.2.1-0.20181127190454-8d0c54c12466/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
@ -204,9 +206,13 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
@ -252,6 +258,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

@ -6,6 +6,11 @@ import (
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common/math"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/internal/utils"
"github.com/ethereum/go-ethereum/common"
@ -23,7 +28,6 @@ const (
FaucetContractBinary = "0x6080604052678ac7230489e8000060015560028054600160a060020a031916331790556101aa806100316000396000f3fe608060405260043610610045577c0100000000000000000000000000000000000000000000000000000000600035046327c78c42811461004a5780634ddd108a1461008c575b600080fd5b34801561005657600080fd5b5061008a6004803603602081101561006d57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166100b3565b005b34801561009857600080fd5b506100a1610179565b60408051918252519081900360200190f35b60025473ffffffffffffffffffffffffffffffffffffffff1633146100d757600080fd5b600154303110156100e757600080fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526020819052604090205460ff161561011a57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116600081815260208190526040808220805460ff1916600190811790915554905181156108fc0292818181858888f19350505050158015610175573d6000803e3d6000fd5b5050565b30319056fea165627a7a723058203e799228fee2fa7c5d15e71c04267a0cc2687c5eff3b48b98f21f355e1064ab30029"
FaucetContractFund = 8000000
FaucetFreeMoneyMethodCall = "0x27c78c42000000000000000000000000"
StakingContractBinary = "0x608060405234801561001057600080fd5b506103f7806100206000396000f3fe608060405260043610610067576000357c01000000000000000000000000000000000000000000000000000000009004806317437a2c1461006c5780632e1a7d4d146100975780638da5cb5b146100e6578063b69ef8a81461013d578063d0e30db014610168575b600080fd5b34801561007857600080fd5b50610081610186565b6040518082815260200191505060405180910390f35b3480156100a357600080fd5b506100d0600480360360208110156100ba57600080fd5b81019080803590602001909291905050506101a5565b6040518082815260200191505060405180910390f35b3480156100f257600080fd5b506100fb6102cd565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561014957600080fd5b506101526102f3565b6040518082815260200191505060405180910390f35b610170610339565b6040518082815260200191505060405180910390f35b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115156102c757816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610280573d6000803e3d6000fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506102c8565b5b919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b6000346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509056fea165627a7a723058204acf95662eb95006df1e0b8ba32316211039c7872bc6eb99d12689c1624143d80029"
)
// AddStakingContractToPendingTransactions adds the deposit smart contract the genesis block.
@ -35,9 +39,9 @@ func (node *Node) AddStakingContractToPendingTransactions() {
//Initially the smart contract should have minimal funds.
contractFunds := big.NewInt(0)
contractFunds = contractFunds.Mul(contractFunds, big.NewInt(params.Ether))
dataEnc := common.FromHex(StakingContractBinary)
dataEnc := common.FromHex(contracts.StakeLockContractBin)
// 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)
mycontracttx, _ := types.SignTx(types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*100, nil, dataEnc), types.HomesteadSigner{}, priKey)
//node.StakingContractAddress = crypto.CreateAddress(contractAddress, uint64(0))
node.StakingContractAddress = node.generateDeployedStakingContractAddress(contractAddress)
node.addPendingTransactions(types.Transactions{mycontracttx})
@ -60,6 +64,55 @@ func (node *Node) generateDeployedStakingContractAddress(contractAddress common.
return crypto.CreateAddress(contractAddress, uint64(nonce))
}
// QueryStakeInfo queries the stake info from the stake contract.
func (node *Node) QueryStakeInfo() *StakeInfo {
abi, err := abi.JSON(strings.NewReader(contracts.StakeLockContractABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
}
bytesData, err := abi.Pack("listLockedAddresses")
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
}
priKey := contract_constants.GenesisBeaconAccountPriKey
deployerAddress := crypto.PubkeyToAddress(priKey.PublicKey)
state, err := node.blockchain.State()
stakingContractAddress := crypto.CreateAddress(deployerAddress, uint64(0))
tx := types.NewTransaction(
state.GetNonce(deployerAddress),
stakingContractAddress,
0,
nil,
math.MaxUint64,
nil,
bytesData,
)
signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, priKey)
if err != nil {
utils.GetLogInstance().Error("Failed to sign contract call tx", "error", err)
return nil
}
output, err := node.ContractCaller.CallContract(signedTx)
if err != nil {
utils.GetLogInstance().Error("Failed to call staking contract", "error", err)
return nil
}
ret := &StakeInfo{}
err = abi.Unpack(ret, "listLockedAddresses", output)
if err != nil {
utils.GetLogInstance().Error("Failed to unpack stake info", "error", err)
return nil
}
return ret
}
// CreateStakingWithdrawTransaction creates a new withdraw stake transaction
func (node *Node) CreateStakingWithdrawTransaction(stake string) (*types.Transaction, error) {
//These should be read from somewhere.

@ -5,10 +5,13 @@ import (
"crypto/ecdsa"
"encoding/binary"
"fmt"
"math/big"
"os"
"sync"
"time"
"github.com/harmony-one/harmony/contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
@ -135,7 +138,7 @@ type Node struct {
serviceManager *service.Manager
//Staked Accounts and Contract
CurrentStakes map[common.Address]int64 //This will save the latest information about staked nodes.
CurrentStakes map[common.Address]*big.Int //This will save the latest information about staked nodes.
StakingContractAddress common.Address
WithdrawStakeFunc []byte
@ -166,6 +169,9 @@ type Node struct {
// map of service type to its message channel.
serviceMessageChan map[service.Type]chan *msg_pb.Message
// Used to call smart contract locally
ContractCaller *contracts.ContractCaller
}
// Blockchain returns the blockchain from node
@ -246,11 +252,13 @@ 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]int64)
node.CurrentStakes = make(map[common.Address]*big.Int)
node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked
node.DepositToStakingAccounts()
}
node.ContractCaller = contracts.NewContractCaller(&db, node.blockchain, params.TestChainConfig)
if consensusObj != nil && consensusObj.IsLeader {
node.State = NodeLeader
go node.ReceiveClientGroupMessage()

@ -289,11 +289,6 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) bool {
// 2. [leader] send new block to the client
func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
utils.GetLogInstance().Info("PostConsensusProcessing")
if node.NodeConfig.Role() == nodeconfig.BeaconLeader {
utils.GetLogInstance().Info("Updating staking list")
node.UpdateStakingList(newBlock)
node.printStakingList()
}
if node.Consensus.IsLeader {
node.BroadcastNewBlock(newBlock)
}
@ -306,6 +301,12 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
node.ConfirmedBlockChannel <- newBlock
}()
}
if node.NodeConfig.Role() == nodeconfig.BeaconLeader {
utils.GetLogInstance().Info("Updating staking list")
node.UpdateStakingList(node.QueryStakeInfo())
node.printStakingList()
}
}
// AddNewBlock is usedd to add new block into the blockchain.

@ -5,13 +5,15 @@ import (
"math/big"
"os"
"github.com/harmony-one/harmony/core"
"github.com/ethereum/go-ethereum/common"
"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"
)
//constants related to staking
@ -20,55 +22,38 @@ import (
//Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html
const (
// DepositFuncSignature is the func signature for deposit method
DepositFuncSignature = "0xd0e30db0"
withdrawFuncSignature = "0x2e1a7d4d"
funcSingatureBytes = 4
funcSingatureBytes = 4
lockPeriodInEpochs = 3 // This should be in sync with contracts/StakeLockContract.sol
)
// UpdateStakingList updates the stakes of every node.
// TODO: read directly from smart contract, or at least check the receipt also for incompleted transaction.
func (node *Node) UpdateStakingList(block *types.Block) error {
signerType := types.HomesteadSigner{}
txns := block.Transactions()
for i := range txns {
txn := txns[i]
toAddress := txn.To()
if toAddress != nil && *toAddress != node.StakingContractAddress { //Not a address aimed at the staking contract.
continue
}
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 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
// StakeInfo is the struct for the return value of listLockedAddresses func in stake contract.
type StakeInfo struct {
LockedAddresses []common.Address
BlockNums []*big.Int
LockPeriodCounts []*big.Int // The number of locking period the token will be locked.
Amounts []*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]
startEpoch := core.GetEpochFromBlockNumber(blockNum.Uint64())
curEpoch := core.GetEpochFromBlockNumber(node.blockchain.CurrentBlock().NumberU64())
if startEpoch == curEpoch {
continue // The token are counted into stakes at the beginning of next epoch.
}
case withdrawFuncSignature: //withdraw, currently: 0x2e1a7d4d
value := decodeStakeCall(data)
if isPresent {
if node.CurrentStakes[currentSender] > value {
node.CurrentStakes[currentSender] -= value
} else if node.CurrentStakes[currentSender] == value {
delete(node.CurrentStakes, currentSender)
} else {
continue //Overdraft protection.
}
} else {
continue //no-op: a node that is not staked cannot withdraw stake.
if curEpoch-startEpoch <= lockPeriodCount.Uint64()*lockPeriodInEpochs {
node.CurrentStakes[addr] = amount
}
default:
continue //no-op if its not deposit or withdaw
}
}
return nil
}
func (node *Node) printStakingList() {

@ -5,107 +5,50 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"golang.org/x/crypto/sha3"
)
func TestUpdateStakingDeposit(t *testing.T) {
_, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "127.0.0.1", Port: "8882", ConsensusPubKey: pubKey}
validator := p2p.Peer{IP: "127.0.0.1", Port: "8885"}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(host, consensus, nil)
node.CurrentStakes = make(map[common.Address]int64)
DepositContractPriKey, _ := crypto.GenerateKey() //DepositContractPriKey is pk for contract
DepositContractAddress := crypto.PubkeyToAddress(DepositContractPriKey.PublicKey) //DepositContractAddress is the address for the contract
node.StakingContractAddress = DepositContractAddress
node.AccountKey, _ = crypto.GenerateKey()
Address := crypto.PubkeyToAddress(node.AccountKey.PublicKey)
callingFunction := "0xd0e30db0"
amount := new(big.Int)
amount.SetString("10", 10)
dataEnc := common.FromHex(callingFunction) //Deposit Does not take a argument, stake is transferred via amount.
tx1, err := types.SignTx(types.NewTransaction(0, DepositContractAddress, node.Consensus.ShardID, amount, params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey)
var (
amount = big.NewInt(10)
blockNum = big.NewInt(15000)
lockPeriodCount = big.NewInt(1)
testAddress = common.Address{123}
)
var txs []*types.Transaction
txs = append(txs, tx1)
header := &types.Header{Extra: []byte("hello")}
block := types.NewBlock(header, txs, nil)
node.UpdateStakingList(block)
if len(node.CurrentStakes) == 0 {
t.Error("New node's stake was not added")
}
value, ok := node.CurrentStakes[Address]
if !ok {
t.Error("The correct address was not added")
}
if value != 10 {
t.Error("The correct stake value was not added")
}
}
func TestUpdateStakingList(t *testing.T) {
func TestUpdateStakingWithdrawal(t *testing.T) {
_, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "127.0.0.1", Port: "8882", ConsensusPubKey: pubKey}
validator := p2p.Peer{IP: "127.0.0.1", Port: "8885"}
leader := p2p.Peer{IP: "127.0.0.1", Port: "9882", ConsensusPubKey: pubKey}
validator := p2p.Peer{IP: "127.0.0.1", Port: "9885"}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(host, consensus, nil)
node.CurrentStakes = make(map[common.Address]int64)
DepositContractPriKey, _ := crypto.GenerateKey() //DepositContractPriKey is pk for contract
DepositContractAddress := crypto.PubkeyToAddress(DepositContractPriKey.PublicKey) //DepositContractAddress is the address for the contract
node.StakingContractAddress = DepositContractAddress
node.AccountKey, _ = crypto.GenerateKey()
Address := crypto.PubkeyToAddress(node.AccountKey.PublicKey)
initialStake := int64(1010)
node.CurrentStakes[Address] = initialStake //initial stake
withdrawFnSignature := []byte("withdraw(uint256)")
hash := sha3.NewLegacyKeccak256()
hash.Write(withdrawFnSignature)
methodID := hash.Sum(nil)[:4]
for i := 0; i < 5; i++ {
selectedTxs := node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock)
node.Worker.CommitTransactions(selectedTxs)
block, _ := node.Worker.Commit()
amount := "10"
stakeToWithdraw := new(big.Int)
stakeToWithdraw.SetString(amount, 10)
paddedAmount := common.LeftPadBytes(stakeToWithdraw.Bytes(), 32)
node.AddNewBlock(block)
}
remainingStakeShouldBe := initialStake - stakeToWithdraw.Int64()
stakeInfo := &StakeInfo{
[]common.Address{testAddress},
[]*big.Int{blockNum},
[]*big.Int{lockPeriodCount},
[]*big.Int{amount},
}
var dataEnc []byte
dataEnc = append(dataEnc, methodID...)
dataEnc = append(dataEnc, paddedAmount...)
tx, err := types.SignTx(types.NewTransaction(0, DepositContractAddress, node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey)
node.UpdateStakingList(stakeInfo)
var txs []*types.Transaction
txs = append(txs, tx)
header := &types.Header{Extra: []byte("hello")}
block := types.NewBlock(header, txs, nil)
node.UpdateStakingList(block)
currentStake, ok := node.CurrentStakes[Address]
if !ok {
t.Error("The correct address was not present")
}
if currentStake != remainingStakeShouldBe {
t.Error("The correct stake value was not subtracted")
if node.CurrentStakes[testAddress].Cmp(amount) != 0 {
t.Error("Stake Info is not updated correctly")
}
}

@ -0,0 +1,5 @@
#!/usr/bin/env bash
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get -y update
sudo apt-get -y install solc

Binary file not shown.
Loading…
Cancel
Save