You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
5.2 KiB
129 lines
5.2 KiB
package node
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"math/big"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
|
|
"github.com/harmony-one/harmony/internal/params"
|
|
|
|
"github.com/harmony-one/harmony/common/denominations"
|
|
"github.com/harmony-one/harmony/contracts"
|
|
"github.com/harmony-one/harmony/core/types"
|
|
common2 "github.com/harmony-one/harmony/internal/common"
|
|
"github.com/harmony-one/harmony/internal/utils"
|
|
)
|
|
|
|
// Constants related to smart contract.
|
|
const (
|
|
FaucetContractFund = 80000000
|
|
)
|
|
|
|
// BuiltInSC is the type of built-in smart contract in blockchain
|
|
type builtInSC uint
|
|
|
|
// List of smart contract type built-in
|
|
const (
|
|
scFaucet builtInSC = iota
|
|
)
|
|
|
|
// GetNonceOfAddress returns nonce of an address.
|
|
func (node *Node) GetNonceOfAddress(address common.Address) uint64 {
|
|
state, err := node.Blockchain().State()
|
|
if err != nil {
|
|
utils.Logger().Error().Err(err).Msg("Failed to get chain state")
|
|
return 0
|
|
}
|
|
return state.GetNonce(address)
|
|
}
|
|
|
|
// GetBalanceOfAddress returns balance of an address.
|
|
func (node *Node) GetBalanceOfAddress(address common.Address) (*big.Int, error) {
|
|
state, err := node.Blockchain().State()
|
|
if err != nil {
|
|
utils.Logger().Error().Err(err).Msg("Failed to get chain state")
|
|
return nil, err
|
|
}
|
|
balance := big.NewInt(0)
|
|
balance.SetBytes(state.GetBalance(address).Bytes())
|
|
return balance, nil
|
|
}
|
|
|
|
// AddFaucetContractToPendingTransactions adds the faucet contract the genesis block.
|
|
func (node *Node) AddFaucetContractToPendingTransactions() {
|
|
// Add a contract deployment transactionv
|
|
priKey := node.ContractDeployerKey
|
|
dataEnc := common.FromHex(contracts.FaucetBin)
|
|
// Unsigned transaction to avoid the case of transaction address.
|
|
|
|
contractFunds := big.NewInt(FaucetContractFund)
|
|
contractFunds = contractFunds.Mul(contractFunds, big.NewInt(denominations.One))
|
|
mycontracttx, _ := types.SignTx(
|
|
types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*10, nil, dataEnc),
|
|
types.HomesteadSigner{},
|
|
priKey)
|
|
node.ContractAddresses = append(node.ContractAddresses, crypto.CreateAddress(crypto.PubkeyToAddress(priKey.PublicKey), uint64(0)))
|
|
node.addPendingTransactions(types.Transactions{mycontracttx})
|
|
}
|
|
|
|
// CallFaucetContract invokes the faucet contract to give the walletAddress initial money
|
|
func (node *Node) CallFaucetContract(address common.Address) common.Hash {
|
|
if node.NodeConfig.GetNetworkType() == nodeconfig.Mainnet {
|
|
return common.Hash{}
|
|
}
|
|
// Temporary code to workaround explorer issue for searching new addresses (https://github.com/harmony-one/harmony/issues/503)
|
|
nonce := atomic.AddUint64(&node.ContractDeployerCurrentNonce, 1)
|
|
tx, _ := types.SignTx(types.NewTransaction(nonce-1, address, node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, nil), types.HomesteadSigner{}, node.ContractDeployerKey)
|
|
utils.Logger().Info().Str("Address", common2.MustAddressToBech32(address)).Msg("Sending placeholder token to ")
|
|
node.addPendingTransactions(types.Transactions{tx})
|
|
// END Temporary code
|
|
|
|
nonce = atomic.AddUint64(&node.ContractDeployerCurrentNonce, 1)
|
|
return node.callGetFreeTokenWithNonce(address, nonce-1)
|
|
}
|
|
|
|
func (node *Node) callGetFreeToken(address common.Address) common.Hash {
|
|
nonce := atomic.AddUint64(&node.ContractDeployerCurrentNonce, 1)
|
|
return node.callGetFreeTokenWithNonce(address, nonce-1)
|
|
}
|
|
|
|
func (node *Node) callGetFreeTokenWithNonce(address common.Address, nonce uint64) common.Hash {
|
|
abi, err := abi.JSON(strings.NewReader(contracts.FaucetABI))
|
|
if err != nil {
|
|
utils.Logger().Error().Err(err).Msg("Failed to generate faucet contract's ABI")
|
|
return common.Hash{}
|
|
}
|
|
bytesData, err := abi.Pack("request", address)
|
|
if err != nil {
|
|
utils.Logger().Error().Err(err).Msg("Failed to generate ABI function bytes data")
|
|
return common.Hash{}
|
|
}
|
|
if len(node.ContractAddresses) == 0 {
|
|
utils.Logger().Error().Err(err).Msg("Failed to find the contract address")
|
|
return common.Hash{}
|
|
}
|
|
tx, _ := types.SignTx(types.NewTransaction(nonce, node.ContractAddresses[0], node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, bytesData), types.HomesteadSigner{}, node.ContractDeployerKey)
|
|
utils.Logger().Info().Str("Address", common2.MustAddressToBech32(address)).Msg("Sending Free Token to ")
|
|
|
|
node.addPendingTransactions(types.Transactions{tx})
|
|
return tx.Hash()
|
|
}
|
|
|
|
// AddContractKeyAndAddress is used to add smart contract related information when node restart and resume with previous state
|
|
// It supports three kinds of on-chain smart contracts for now.
|
|
func (node *Node) AddContractKeyAndAddress(t builtInSC) {
|
|
switch t {
|
|
case scFaucet:
|
|
// faucet contract
|
|
contractDeployerKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time"))
|
|
node.ContractDeployerKey = contractDeployerKey
|
|
node.ContractAddresses = append(node.ContractAddresses, crypto.CreateAddress(crypto.PubkeyToAddress(contractDeployerKey.PublicKey), uint64(0)))
|
|
default:
|
|
utils.Logger().Error().Interface("unknown SC", t).Msg("AddContractKeyAndAddress")
|
|
}
|
|
}
|
|
|