clean up smart contract code

pull/952/head
Minh Doan 6 years ago committed by Minh Doan
parent 26efc233d7
commit f77508ae84
  1. 36
      node/contract_test.go
  2. 215
      node/demo_contract.go
  3. 6
      node/node.go
  4. 228
      node/puzzle_contract.go

@ -1,36 +0,0 @@
package node
import (
"testing"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
)
func prepareNode(t *testing.T) *Node {
pubKey := bls.RandPrivateKey().GetPublicKey()
leader := p2p.Peer{IP: "127.0.0.1", Port: "8882", ConsensusPubKey: pubKey}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus, err := consensus.New(host, 0, leader, nil)
if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err)
}
return New(host, consensus, testDBFactory, false)
}
func TestAddLotteryContract(t *testing.T) {
node := prepareNode(t)
node.AddLotteryContract()
if len(node.DemoContractAddress) == 0 {
t.Error("Can not create demo contract")
}
}

@ -1,215 +0,0 @@
package node
import (
"fmt"
"math"
"math/big"
"os"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
contract_constants "github.com/harmony-one/harmony/internal/utils/contract"
)
// Constants for lottery.
const (
Enter = "enter"
PickWinner = "pickWinner"
GetPlayers = "getPlayers"
PuzzleFund = 100000000
)
// AddLotteryContract adds the demo lottery contract the genesis block.
func (node *Node) AddLotteryContract() {
// Add a lottery demo contract.
priKey, err := crypto.HexToECDSA(contract_constants.DemoAccounts[0].Private)
if err != nil {
utils.GetLogInstance().Error("Error when creating private key for demo contract")
// Exit here to recognize the coding working.
// Basically we will remove this logic when launching so it's fine for now.
os.Exit(1)
}
dataEnc := common.FromHex(contracts.LotteryBin)
// Unsigned transaction to avoid the case of transaction address.
contractFunds := big.NewInt(0)
contractFunds = contractFunds.Mul(contractFunds, big.NewInt(params.Ether))
demoContract, _ := types.SignTx(
types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*10, nil, dataEnc),
types.HomesteadSigner{},
priKey)
node.DemoContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(priKey.PublicKey), uint64(0))
node.LotteryManagerPrivateKey = priKey
node.addPendingTransactions(types.Transactions{demoContract})
}
// CreateTransactionForEnterMethod generates transaction for enter method and add it into pending tx list.
func (node *Node) CreateTransactionForEnterMethod(amount int64, priKey string) error {
var err error
toAddress := node.DemoContractAddress
abi, err := abi.JSON(strings.NewReader(contracts.LotteryABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
return err
}
bytesData, err := abi.Pack(Enter)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
return err
}
key, err := crypto.HexToECDSA(priKey)
nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(key.PublicKey))
Amount := big.NewInt(amount)
Amount = Amount.Mul(Amount, big.NewInt(params.Ether))
tx := types.NewTransaction(
nonce,
toAddress,
node.NodeConfig.ShardID,
Amount,
params.TxGas*10,
nil,
bytesData,
)
if err != nil {
utils.GetLogInstance().Error("Failed to get private key", "error", err)
return err
}
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key); err == nil {
node.addPendingTransactions(types.Transactions{signedTx})
return nil
}
utils.GetLogInstance().Error("Unable to call enter method", "error", err)
return err
}
// GetResultDirectly get current players and their balances, not from smart contract.
func (node *Node) GetResultDirectly(priKey string) (players []string, balances []*big.Int) {
for _, account := range contract_constants.DemoAccounts {
players = append(players, account.Private)
key, err := crypto.HexToECDSA(account.Private)
if err != nil {
utils.GetLogInstance().Error("Error when HexToECDSA")
}
address := crypto.PubkeyToAddress(key.PublicKey)
balance, err := node.GetBalanceOfAddress(address)
balances = append(balances, balance)
}
return players, balances
}
// GenerateResultDirectly get current players and their balances, not from smart contract.
func (node *Node) GenerateResultDirectly(addresses []common.Address) (players []string, balances []*big.Int) {
for _, address := range addresses {
players = append(players, address.String())
balance, _ := node.GetBalanceOfAddress(address)
balances = append(balances, balance)
}
fmt.Println("generate result", players, balances)
return players, balances
}
// GetResult get current players and their balances.
func (node *Node) GetResult(priKey string) (players []string, balances []*big.Int) {
// TODO(minhdoan): get result from smart contract is current not working. Fix it later.
abi, err := abi.JSON(strings.NewReader(contracts.LotteryABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
}
bytesData, err := abi.Pack("getPlayers")
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
}
demoContractAddress := node.DemoContractAddress
key, err := crypto.HexToECDSA(priKey)
if err != nil {
utils.GetLogInstance().Error("Failed to parse private key", "error", err)
}
nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(key.PublicKey))
tx := types.NewTransaction(
nonce,
demoContractAddress,
node.NodeConfig.ShardID,
nil,
math.MaxUint64,
nil,
bytesData,
)
signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key)
if err != nil {
utils.GetLogInstance().Error("Failed to sign contract call tx", "error", err)
return nil, nil
}
output, err := node.ContractCaller.CallContract(signedTx)
if err != nil {
utils.GetLogInstance().Error("Failed to call staking contract", "error", err)
return nil, nil
}
ret := []common.Address{}
err = abi.Unpack(&ret, "getPlayers", output)
if err != nil {
utils.GetLogInstance().Error("Failed to unpack getPlayers", "error", err)
return nil, nil
}
utils.GetLogInstance().Info("get result: ", "ret", ret)
fmt.Println("get result called:", ret)
return node.GenerateResultDirectly(ret)
}
// CreateTransactionForPickWinner generates transaction for enter method and add it into pending tx list.
func (node *Node) CreateTransactionForPickWinner() error {
var err error
toAddress := node.DemoContractAddress
abi, err := abi.JSON(strings.NewReader(contracts.LotteryABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
return err
}
bytesData, err := abi.Pack(PickWinner)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
return err
}
key := node.LotteryManagerPrivateKey
if key == nil {
return fmt.Errorf("LotterManagerPrivateKey is nil")
}
nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(key.PublicKey))
Amount := big.NewInt(0)
tx := types.NewTransaction(
nonce,
toAddress,
node.NodeConfig.ShardID,
Amount,
params.TxGas*1000,
nil,
bytesData,
)
if err != nil {
utils.GetLogInstance().Error("Failed to get private key", "error", err)
return err
}
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key); err == nil {
node.addPendingTransactions(types.Transactions{signedTx})
return nil
}
utils.GetLogInstance().Error("Unable to call enter method", "error", err)
return err
}

@ -15,7 +15,6 @@ import (
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/api/client"
clientService "github.com/harmony-one/harmony/api/client/service"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
"github.com/harmony-one/harmony/api/service"
"github.com/harmony-one/harmony/api/service/syncing"
@ -69,8 +68,6 @@ func (state State) String() string {
}
const (
// ClientServicePortDiff is the positive port diff for client service
ClientServicePortDiff = 5555
maxBroadcastNodes = 10 // broadcast at most maxBroadcastNodes peers that need in sync
broadcastTimeout int64 = 3 * 60 * 1000000000 // 3 mins
//SyncIDLength is the length of bytes for syncID
@ -115,9 +112,6 @@ type Node struct {
Worker *worker.Worker
BeaconWorker *worker.Worker // worker for beacon chain
// Client server (for wallet requests)
clientServer *clientService.Server
// Syncing component.
syncID [SyncIDLength]byte // a unique ID for the node during the state syncing process with peers
downloaderServer *downloader.Server

@ -1,228 +0,0 @@
package node
import (
"fmt"
"math/big"
"os"
"strings"
"sync/atomic"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
contract_constants "github.com/harmony-one/harmony/internal/utils/contract"
)
// Constants for puzzle.
const (
Play = "play"
Payout = "payout"
EndGame = "endGame"
)
// OneEther is one ether
var OneEther = big.NewInt(params.Ether)
// AddPuzzleContract adds the demo puzzle contract the genesis block.
func (node *Node) AddPuzzleContract() {
// Add a puzzle demo contract.
priKey, err := crypto.HexToECDSA(contract_constants.PuzzleAccounts[0].Private)
if err != nil {
utils.GetLogInstance().Error("Error when creating private key for puzzle demo contract")
// Exit here to recognize the coding working.
// Basically we will remove this logic when launching so it's fine for now.
os.Exit(1)
}
dataEnc := common.FromHex(contracts.PuzzleBin)
// Unsigned transaction to avoid the case of transaction address.
contractFunds := big.NewInt(PuzzleFund)
contractFunds = contractFunds.Mul(contractFunds, big.NewInt(params.Ether))
demoContract, _ := types.SignTx(
types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*1000, nil, dataEnc),
types.HomesteadSigner{},
priKey)
node.PuzzleContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(priKey.PublicKey), uint64(0))
node.PuzzleManagerPrivateKey = priKey
node.addPendingTransactions(types.Transactions{demoContract})
}
// CreateTransactionForPlayMethod generates transaction for play method and add it into pending tx list.
func (node *Node) CreateTransactionForPlayMethod(priKey string, amount int64) (string, error) {
var err error
toAddress := node.PuzzleContractAddress
abi, err := abi.JSON(strings.NewReader(contracts.PuzzleABI))
if err != nil {
utils.GetLogInstance().Error("puzzle-play: Failed to generate staking contract's ABI", "error", err)
return "", err
}
bytesData, err := abi.Pack(Play)
if err != nil {
utils.GetLogInstance().Error("puzzle-play: Failed to generate ABI function bytes data", "error", err)
return "", err
}
Stake := big.NewInt(0)
Stake = Stake.Mul(OneEther, big.NewInt(amount))
key, err := crypto.HexToECDSA(priKey)
if err != nil {
utils.GetLogInstance().Error("Failed to parse private key", "error", err)
return "", err
}
address := crypto.PubkeyToAddress(key.PublicKey)
balance, err := node.GetBalanceOfAddress(address)
if err != nil {
utils.GetLogInstance().Error("puzzle-play: can not get address", "error", err)
return "", err
} else if balance.Cmp(Stake) == -1 {
utils.GetLogInstance().Error("puzzle-play: insufficient fund", "error", err, "stake", Stake, "balance", balance)
return "", ErrPuzzleInsufficientFund
}
nonce := node.GetAndIncreaseAddressNonce(address)
tx := types.NewTransaction(
nonce,
toAddress,
node.NodeConfig.ShardID,
Stake,
params.TxGas*100,
nil,
bytesData,
)
if err != nil {
utils.GetLogInstance().Error("puzzle-play: Failed to get private key", "error", err)
return "", err
}
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key); err == nil {
node.addPendingTransactions(types.Transactions{signedTx})
return signedTx.Hash().Hex(), nil
}
utils.GetLogInstance().Error("puzzle-play: Unable to call enter method", "error", err)
return "", err
}
// CreateTransactionForPayoutMethod generates transaction for payout method and add it into pending tx list.
func (node *Node) CreateTransactionForPayoutMethod(priKey string, level int, sequence string) (string, error) {
var err error
toAddress := node.PuzzleContractAddress
abi, err := abi.JSON(strings.NewReader(contracts.PuzzleABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
return "", err
}
key, err := crypto.HexToECDSA(priKey)
if err != nil {
utils.GetLogInstance().Error("Failed to parse private key", "error", err)
return "", err
}
address := crypto.PubkeyToAddress(key.PublicKey)
// add params for address payable player, uint8 new_level, steps string
fmt.Println("Payout: address", address)
bytesData, err := abi.Pack(Payout, address, big.NewInt(int64(level)), sequence)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
return "", err
}
if key == nil {
return "", fmt.Errorf("user key is nil")
}
nonce := node.GetAndIncreaseAddressNonce(address)
Amount := big.NewInt(0)
tx := types.NewTransaction(
nonce,
toAddress,
node.NodeConfig.ShardID,
Amount,
params.TxGas*10,
nil,
bytesData,
)
if err != nil {
utils.GetLogInstance().Error("Failed to get private key", "error", err)
return "", err
}
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key); err == nil {
node.addPendingTransactions(types.Transactions{signedTx})
return signedTx.Hash().Hex(), nil
}
utils.GetLogInstance().Error("Unable to call enter method", "error", err)
return "", err
}
// CreateTransactionForEndMethod generates transaction for endGame method and add it into pending tx list.
func (node *Node) CreateTransactionForEndMethod(priKey string) (string, error) {
var err error
toAddress := node.PuzzleContractAddress
abi, err := abi.JSON(strings.NewReader(contracts.PuzzleABI))
if err != nil {
utils.GetLogInstance().Error("Failed to generate staking contract's ABI", "error", err)
return "", err
}
key, err := crypto.HexToECDSA(priKey)
if err != nil {
utils.GetLogInstance().Error("Failed to parse private key", "error", err)
return "", err
}
address := crypto.PubkeyToAddress(key.PublicKey)
// add params for address payable player, uint8 new_level, steps string
fmt.Println("EndGame: address", address)
bytesData, err := abi.Pack(EndGame, address)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
return "", err
}
if key == nil {
return "", fmt.Errorf("user key is nil")
}
nonce := node.GetAndIncreaseAddressNonce(address)
Amount := big.NewInt(0)
tx := types.NewTransaction(
nonce,
toAddress,
node.NodeConfig.ShardID,
Amount,
params.TxGas*10,
nil,
bytesData,
)
if err != nil {
utils.GetLogInstance().Error("Failed to get private key", "error", err)
return "", err
}
if signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, key); err == nil {
node.addPendingTransactions(types.Transactions{signedTx})
return signedTx.Hash().Hex(), nil
}
utils.GetLogInstance().Error("Unable to call enter method", "error", err)
return "", err
}
// GetAndIncreaseAddressNonce get and increase the address's nonce
func (node *Node) GetAndIncreaseAddressNonce(address common.Address) uint64 {
if value, ok := node.AddressNonce.Load(address); ok {
n, ok := value.(uint64)
if !ok {
return 0
}
nonce := atomic.AddUint64(&n, 1)
return nonce - 1
}
nonce := node.GetNonceOfAddress(address) + 1
node.AddressNonce.Store(address, nonce)
return nonce - 1
}
Loading…
Cancel
Save