add puzzle contract

smart contract integrate smart contract

add payout call and fix others

fix play contract call
pull/793/head
Minh Doan 6 years ago
parent e0e4bfaffe
commit cc32242962
  1. 92
      api/service/restclientsupport/service.go
  2. 2
      cmd/restclientsupport/main.go
  3. 268
      contracts/Puzzle.go
  4. 37
      contracts/Puzzle.sol
  5. 3
      contracts/gen.sh
  6. 16
      internal/utils/contract/constants.go
  7. 5
      node/contract.go
  8. 2
      node/demo_contract.go
  9. 2
      node/errors.go
  10. 6
      node/node.go
  11. 146
      node/puzzle_contract.go
  12. 4
      node/service_setup.go

@ -27,14 +27,16 @@ const (
// Service is the struct for rest client support service. // Service is the struct for rest client support service.
type Service struct { type Service struct {
router *mux.Router router *mux.Router
server *http.Server server *http.Server
CreateTransactionForEnterMethod func(int64, string) error CreateTransactionForEnterMethod func(int64, string) error
GetResult func(string) ([]string, []*big.Int) GetResult func(string) ([]string, []*big.Int)
CreateTransactionForPickWinner func() error CreateTransactionForPickWinner func() error
messageChan chan *msg_pb.Message messageChan chan *msg_pb.Message
CallFaucetContract func(common.Address) common.Hash CallFaucetContract func(common.Address) common.Hash
GetAccountBalance func(common.Address) (*big.Int, error) GetAccountBalance func(common.Address) (*big.Int, error)
CreateTransactionForPlayMethod func(string) error
CreateTransactionForPayoutMethod func(string, int) error
} }
// New returns new client support service. // New returns new client support service.
@ -42,13 +44,17 @@ func New(
CreateTransactionForEnterMethod func(int64, string) error, CreateTransactionForEnterMethod func(int64, string) error,
GetResult func(string) ([]string, []*big.Int), GetResult func(string) ([]string, []*big.Int),
CreateTransactionForPickWinner func() error, CreateTransactionForPickWinner func() error,
CallFaucetContract func(common.Address) common.Hash, GetAccountBalance func(common.Address) (*big.Int, error)) *Service { CallFaucetContract func(common.Address) common.Hash, GetAccountBalance func(common.Address) (*big.Int, error),
CreateTransactionForPlayMethod func(string) error,
CreateTransactionForPayoutMethod func(string, int) error) *Service {
return &Service{ return &Service{
CreateTransactionForEnterMethod: CreateTransactionForEnterMethod, CreateTransactionForEnterMethod: CreateTransactionForEnterMethod,
GetResult: GetResult, GetResult: GetResult,
CreateTransactionForPickWinner: CreateTransactionForPickWinner, CreateTransactionForPickWinner: CreateTransactionForPickWinner,
CallFaucetContract: CallFaucetContract, CallFaucetContract: CallFaucetContract,
GetAccountBalance: GetAccountBalance, GetAccountBalance: GetAccountBalance,
CreateTransactionForPlayMethod: CreateTransactionForPlayMethod,
CreateTransactionForPayoutMethod: CreateTransactionForPayoutMethod,
} }
} }
@ -93,6 +99,12 @@ func (s *Service) Run() *http.Server {
// Set up router for winner. // Set up router for winner.
s.router.Path("/winner").HandlerFunc(s.Winner) s.router.Path("/winner").HandlerFunc(s.Winner)
// Routing for puzzle app.
// Set up router for play.
s.router.Path("/play").HandlerFunc(s.Play)
// Set up router for payout.
s.router.Path("/payout").HandlerFunc(s.Payout)
// Do serving now. // Do serving now.
utils.GetLogInstance().Info("Listening on ", "port: ", Port) utils.GetLogInstance().Info("Listening on ", "port: ", Port)
server := &http.Server{Addr: addr, Handler: s.router} server := &http.Server{Addr: addr, Handler: s.router}
@ -226,6 +238,58 @@ func (s *Service) Winner(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(res) json.NewEncoder(w).Encode(res)
} }
// Play triggers play method of puzzle smart contract.
func (s *Service) Play(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
key := r.FormValue("key")
fmt.Println("puzzle-play", key)
res := &Response{
Success: false,
}
if s.CreateTransactionForPlayMethod == nil {
fmt.Println("puzzle-play no method", key)
json.NewEncoder(w).Encode(res)
return
}
if err := s.CreateTransactionForPlayMethod(key); err != nil {
utils.GetLogInstance().Error("puzzle-play, error", err)
json.NewEncoder(w).Encode(res)
return
}
res.Success = true
json.NewEncoder(w).Encode(res)
}
// Payout triggers play payout of puzzle smart contract.
func (s *Service) Payout(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
key := r.FormValue("key")
newLevel := r.FormValue("new_level")
fmt.Println("payout: key", key, "new_level", newLevel)
newLevelInt, err := strconv.Atoi(newLevel)
fmt.Println("play")
res := &Response{
Success: false,
}
if s.CreateTransactionForPayoutMethod == nil {
json.NewEncoder(w).Encode(res)
return
}
if err = s.CreateTransactionForPayoutMethod(key, newLevelInt); err != nil {
utils.GetLogInstance().Error("error", err)
json.NewEncoder(w).Encode(res)
return
}
res.Success = true
json.NewEncoder(w).Encode(res)
}
// NotifyService notify service // NotifyService notify service
func (s *Service) NotifyService(params map[string]interface{}) { func (s *Service) NotifyService(params map[string]interface{}) {
return return

@ -7,7 +7,7 @@ import (
) )
func main() { func main() {
s := restclientsupport.New(nil, nil, nil, nil, nil) s := restclientsupport.New(nil, nil, nil, nil, nil, nil, nil)
s.StartService() s.StartService()
fmt.Println("Server started") fmt.Println("Server started")
select {} select {}

@ -0,0 +1,268 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package contracts
import (
"strings"
"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"
)
// PuzzleABI is the input ABI used to generate the binding from.
const PuzzleABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"level_map\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"player\",\"type\":\"address\"},{\"name\":\"new_level\",\"type\":\"uint8\"}],\"name\":\"payout\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"manager\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"play\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"
// PuzzleBin is the compiled bytecode used for deploying new contracts.
const PuzzleBin = `0x608060405260008054600160a060020a031916331790556103be806100256000396000f3fe60806040526004361061005b577c0100000000000000000000000000000000000000000000000000000000600035046311b88fef8114610060578063158b4aa6146100a9578063481c6a75146100da57806393e84cd91461010b575b600080fd5b34801561006c57600080fd5b506100936004803603602081101561008357600080fd5b5035600160a060020a0316610113565b6040805160ff9092168252519081900360200190f35b6100d8600480360360408110156100bf57600080fd5b508035600160a060020a0316906020013560ff16610128565b005b3480156100e657600080fd5b506100ef6102da565b60408051600160a060020a039092168252519081900360200190f35b6100d86102e9565b60016020526000908152604090205460ff1681565b60005460408051808201909152601381527f556e617574686f72697a65642041636365737300000000000000000000000000602082015290600160a060020a0316331461020d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156101d25781810151838201526020016101ba565b50505050905090810190601f1680156101ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600160a060020a03821660009081526001602052604090205460ff90811690821681116102b457604051600160a060020a0384169067ffffffffffffffff670de0b6b3a764000060ff60026001878903010216021680156108fc02916000818181858888f19350505050158015610289573d6000803e3d6000fd5b50600160a060020a0383166000908152600160205260409020805460ff191660ff84161790556102d5565b600160a060020a0383166000908152600160205260409020805460ff191690555b505050565b600054600160a060020a031681565b60408051808201909152601181527f496e73756666696369656e742046756e640000000000000000000000000000006020820152671bc16d674ec8000034101561038f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156101d25781810151838201526020016101ba565b5056fea165627a7a72305820dcdfb1bf37c0dddda1b2ec670fa6ef6c8913a8b4b6e815bf184697e5da7b0d1c0029`
// DeployPuzzle deploys a new Ethereum contract, binding an instance of Puzzle to it.
func DeployPuzzle(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Puzzle, error) {
parsed, err := abi.JSON(strings.NewReader(PuzzleABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PuzzleBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &Puzzle{PuzzleCaller: PuzzleCaller{contract: contract}, PuzzleTransactor: PuzzleTransactor{contract: contract}, PuzzleFilterer: PuzzleFilterer{contract: contract}}, nil
}
// Puzzle is an auto generated Go binding around an Ethereum contract.
type Puzzle struct {
PuzzleCaller // Read-only binding to the contract
PuzzleTransactor // Write-only binding to the contract
PuzzleFilterer // Log filterer for contract events
}
// PuzzleCaller is an auto generated read-only Go binding around an Ethereum contract.
type PuzzleCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PuzzleTransactor is an auto generated write-only Go binding around an Ethereum contract.
type PuzzleTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PuzzleFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type PuzzleFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PuzzleSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type PuzzleSession struct {
Contract *Puzzle // 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
}
// PuzzleCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type PuzzleCallerSession struct {
Contract *PuzzleCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// PuzzleTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type PuzzleTransactorSession struct {
Contract *PuzzleTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// PuzzleRaw is an auto generated low-level Go binding around an Ethereum contract.
type PuzzleRaw struct {
Contract *Puzzle // Generic contract binding to access the raw methods on
}
// PuzzleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type PuzzleCallerRaw struct {
Contract *PuzzleCaller // Generic read-only contract binding to access the raw methods on
}
// PuzzleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type PuzzleTransactorRaw struct {
Contract *PuzzleTransactor // Generic write-only contract binding to access the raw methods on
}
// NewPuzzle creates a new instance of Puzzle, bound to a specific deployed contract.
func NewPuzzle(address common.Address, backend bind.ContractBackend) (*Puzzle, error) {
contract, err := bindPuzzle(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &Puzzle{PuzzleCaller: PuzzleCaller{contract: contract}, PuzzleTransactor: PuzzleTransactor{contract: contract}, PuzzleFilterer: PuzzleFilterer{contract: contract}}, nil
}
// NewPuzzleCaller creates a new read-only instance of Puzzle, bound to a specific deployed contract.
func NewPuzzleCaller(address common.Address, caller bind.ContractCaller) (*PuzzleCaller, error) {
contract, err := bindPuzzle(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &PuzzleCaller{contract: contract}, nil
}
// NewPuzzleTransactor creates a new write-only instance of Puzzle, bound to a specific deployed contract.
func NewPuzzleTransactor(address common.Address, transactor bind.ContractTransactor) (*PuzzleTransactor, error) {
contract, err := bindPuzzle(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &PuzzleTransactor{contract: contract}, nil
}
// NewPuzzleFilterer creates a new log filterer instance of Puzzle, bound to a specific deployed contract.
func NewPuzzleFilterer(address common.Address, filterer bind.ContractFilterer) (*PuzzleFilterer, error) {
contract, err := bindPuzzle(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &PuzzleFilterer{contract: contract}, nil
}
// bindPuzzle binds a generic wrapper to an already deployed contract.
func bindPuzzle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(PuzzleABI))
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 (_Puzzle *PuzzleRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _Puzzle.Contract.PuzzleCaller.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 (_Puzzle *PuzzleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Puzzle.Contract.PuzzleTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Puzzle *PuzzleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Puzzle.Contract.PuzzleTransactor.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 (_Puzzle *PuzzleCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _Puzzle.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 (_Puzzle *PuzzleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Puzzle.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Puzzle *PuzzleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Puzzle.Contract.contract.Transact(opts, method, params...)
}
// LevelMap is a free data retrieval call binding the contract method 0x11b88fef.
//
// Solidity: function level_map( address) constant returns(uint8)
func (_Puzzle *PuzzleCaller) LevelMap(opts *bind.CallOpts, arg0 common.Address) (uint8, error) {
var (
ret0 = new(uint8)
)
out := ret0
err := _Puzzle.contract.Call(opts, out, "level_map", arg0)
return *ret0, err
}
// LevelMap is a free data retrieval call binding the contract method 0x11b88fef.
//
// Solidity: function level_map( address) constant returns(uint8)
func (_Puzzle *PuzzleSession) LevelMap(arg0 common.Address) (uint8, error) {
return _Puzzle.Contract.LevelMap(&_Puzzle.CallOpts, arg0)
}
// LevelMap is a free data retrieval call binding the contract method 0x11b88fef.
//
// Solidity: function level_map( address) constant returns(uint8)
func (_Puzzle *PuzzleCallerSession) LevelMap(arg0 common.Address) (uint8, error) {
return _Puzzle.Contract.LevelMap(&_Puzzle.CallOpts, arg0)
}
// Manager is a free data retrieval call binding the contract method 0x481c6a75.
//
// Solidity: function manager() constant returns(address)
func (_Puzzle *PuzzleCaller) Manager(opts *bind.CallOpts) (common.Address, error) {
var (
ret0 = new(common.Address)
)
out := ret0
err := _Puzzle.contract.Call(opts, out, "manager")
return *ret0, err
}
// Manager is a free data retrieval call binding the contract method 0x481c6a75.
//
// Solidity: function manager() constant returns(address)
func (_Puzzle *PuzzleSession) Manager() (common.Address, error) {
return _Puzzle.Contract.Manager(&_Puzzle.CallOpts)
}
// Manager is a free data retrieval call binding the contract method 0x481c6a75.
//
// Solidity: function manager() constant returns(address)
func (_Puzzle *PuzzleCallerSession) Manager() (common.Address, error) {
return _Puzzle.Contract.Manager(&_Puzzle.CallOpts)
}
// Payout is a paid mutator transaction binding the contract method 0x158b4aa6.
//
// Solidity: function payout(player address, new_level uint8) returns()
func (_Puzzle *PuzzleTransactor) Payout(opts *bind.TransactOpts, player common.Address, new_level uint8) (*types.Transaction, error) {
return _Puzzle.contract.Transact(opts, "payout", player, new_level)
}
// Payout is a paid mutator transaction binding the contract method 0x158b4aa6.
//
// Solidity: function payout(player address, new_level uint8) returns()
func (_Puzzle *PuzzleSession) Payout(player common.Address, new_level uint8) (*types.Transaction, error) {
return _Puzzle.Contract.Payout(&_Puzzle.TransactOpts, player, new_level)
}
// Payout is a paid mutator transaction binding the contract method 0x158b4aa6.
//
// Solidity: function payout(player address, new_level uint8) returns()
func (_Puzzle *PuzzleTransactorSession) Payout(player common.Address, new_level uint8) (*types.Transaction, error) {
return _Puzzle.Contract.Payout(&_Puzzle.TransactOpts, player, new_level)
}
// Play is a paid mutator transaction binding the contract method 0x93e84cd9.
//
// Solidity: function play() returns()
func (_Puzzle *PuzzleTransactor) Play(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Puzzle.contract.Transact(opts, "play")
}
// Play is a paid mutator transaction binding the contract method 0x93e84cd9.
//
// Solidity: function play() returns()
func (_Puzzle *PuzzleSession) Play() (*types.Transaction, error) {
return _Puzzle.Contract.Play(&_Puzzle.TransactOpts)
}
// Play is a paid mutator transaction binding the contract method 0x93e84cd9.
//
// Solidity: function play() returns()
func (_Puzzle *PuzzleTransactorSession) Play() (*types.Transaction, error) {
return _Puzzle.Contract.Play(&_Puzzle.TransactOpts)
}

@ -0,0 +1,37 @@
pragma solidity >=0.4.22;
contract Puzzle {
string internal constant INSUFFICIENT_FUND_MESSAGE = "Insufficient Fund";
string internal constant RESTRICTED_MESSAGE = "Unauthorized Access";
address public manager; // The adress of the owner of this contract
mapping(address => uint8) public level_map;
constructor() public payable {
manager = msg.sender;
}
/**
* @dev The player enters into the current game session by
* paying at least 2 token.
*/
function play() public payable {
require(msg.value >= 2 ether, INSUFFICIENT_FUND_MESSAGE);
}
/**
* @dev pay the player if they have crossed their last best level.
*/
function payout(address payable player, uint8 new_level) public payable restricted {
uint8 cur_level = level_map[player];
if (new_level >= cur_level) {
player.transfer(2 * (new_level - cur_level + 1) * 1 ether);
level_map[player] = new_level;
} else {
delete level_map[player];
}
}
modifier restricted() {
require(msg.sender == manager, RESTRICTED_MESSAGE);
_;
}
}

@ -1,3 +1,4 @@
abigen -sol Lottery.sol -out Lottery.go --pkg contracts # abigen -sol Lottery.sol -out Lottery.go --pkg contracts
abigen -sol Puzzle.sol -out Puzzle.go --pkg contracts
# abigen -sol Faucet.sol -out Faucet.go --pkg contracts # abigen -sol Faucet.sol -out Faucet.go --pkg contracts
abigen -sol StakeLockContract.sol -out StakeLockContract.go --pkg contracts abigen -sol StakeLockContract.sol -out StakeLockContract.go --pkg contracts

@ -883,6 +883,22 @@ var DemoAccounts = [...]DeployAccount{
{Address: "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8", Private: "3c8642f7188e05acc4467d9e2aa7fd539e82aa90a5497257cf0ecbb98ed3b88f", Public: "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8"}, {Address: "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8", Private: "3c8642f7188e05acc4467d9e2aa7fd539e82aa90a5497257cf0ecbb98ed3b88f", Public: "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8"},
} }
// PuzzleAccounts is the accounts used for lottery demo.
var PuzzleAccounts = [...]DeployAccount{
{Address: "0xBE3958eD7A723Cb6fFF92b0B07682672B2AbD15A", Private: "0e9ee528c878a492ee6ae645ad31656239bb12536377aeff1e7aa521dd5848c9", Public: "0xBE3958eD7A723Cb6fFF92b0B07682672B2AbD15A"},
{Address: "0x87A4c9209d7DD8aBDcE2285cB0FF4b2015A80f95", Private: "8d95c5b66b15a162c9bfcbfe0de041fe328e489f50af0fd9772a4251d090179c", Public: "0x87A4c9209d7DD8aBDcE2285cB0FF4b2015A80f95"},
{Address: "0x92f65ed2bB5DaeA77c6Ca22BA38ca4B4c2443AbB", Private: "86ba356093c54f6557faa8aa28abd89fb843462226c6822ffcaf1bebfc572107", Public: "0x92f65ed2bB5DaeA77c6Ca22BA38ca4B4c2443AbB"},
{Address: "0x352f4b24BCEDdA13B7263D347656f104Bc4Ac06F", Private: "9f4fb861c4b81285d5a0cd040ea937f7fcc33eba14cc0da550d201454d67f45e", Public: "0x352f4b24BCEDdA13B7263D347656f104Bc4Ac06F"},
{Address: "0xfc7e61314D41511e783382bde2aF63a8Ba35942f", Private: "bc8a2cde3a38168d86c2e1f8d3246c4d13ff17446dc3b9954a6b5c158d1f587f", Public: "0xfc7e61314D41511e783382bde2aF63a8Ba35942f"},
{Address: "0x1A5728b833E734a73e3dfB4dD72da35eB2fcd902", Private: "45172a91c871365754788ad8db59f7e24a848861c7cbfa69e4577885ddde06b5", Public: "0x1A5728b833E734a73e3dfB4dD72da35eB2fcd902"},
{Address: "0xc4bac29A908FD312254bdf2Cc0Ad953eC3D3C9f8", Private: "8ef36cfe78ade686167d1b01674679e954f0f3fbdd5a5517229d8ce7e82c2a98", Public: "0xc4bac29A908FD312254bdf2Cc0Ad953eC3D3C9f8"},
{Address: "0x450ee67054761078Dfa05C347A5dDbA0eEB40a1B", Private: "12614ab17446556bd355912b3d58f106776e6704c935c7d21e44a49dabc145d1", Public: "0x450ee67054761078Dfa05C347A5dDbA0eEB40a1B"},
{Address: "0xA01d28C5B8555C999A4ccE0Ef1F766b74971469f", Private: "0501438b5597142e6b66fa5901d774d2c010e56457b4c2aefc9e0b3796dc6035", Public: "0xA01d28C5B8555C999A4ccE0Ef1F766b74971469f"},
{Address: "0xa97a0bc3ab0615bd52f607Bc73f641225c753A1B", Private: "c97cd7c35a8f189fdcd05c0f3799343300272d64bb30914a839a97361e248c6b", Public: "0xa97a0bc3ab0615bd52f607Bc73f641225c753A1B"},
{Address: "0x931F6E2f7D75b3A3674Db7f377270bC2D7E85a0b", Private: "b958996cef750ca565604e04c30034c8e77e06523751cac5cdc14ba22f01ca70", Public: "0x931F6E2f7D75b3A3674Db7f377270bC2D7E85a0b"},
{Address: "0xB3AE88dF65D0871e9cF11798c1eC496C7A0109CC", Private: "c2cb484f137c71a5ccc45f9e46d579970667ee6d23833c03c1c2b48900807b0c", Public: "0xB3AE88dF65D0871e9cF11798c1eC496C7A0109CC"},
}
// NewNodeAccounts is the accounts used for new node to stake and join the network. // NewNodeAccounts is the accounts used for new node to stake and join the network.
var NewNodeAccounts = [...]DeployAccount{ var NewNodeAccounts = [...]DeployAccount{
{Address: "0xa2F8b3bf3ea7b46576F3a7be105d7F74186df42d", Private: "8ca12c7fa1f54406b518cc3ca78bad9c3fb7206fad3a258d6583e0a31a52e2ce", Public: "0xa2F8b3bf3ea7b46576F3a7be105d7F74186df42d"}, {Address: "0xa2F8b3bf3ea7b46576F3a7be105d7F74186df42d", Private: "8ca12c7fa1f54406b518cc3ca78bad9c3fb7206fad3a258d6583e0a31a52e2ce", Public: "0xa2F8b3bf3ea7b46576F3a7be105d7F74186df42d"},

@ -32,6 +32,7 @@ const (
scFaucet builtInSC = iota scFaucet builtInSC = iota
scStaking scStaking
scLottery scLottery
scPuzzle
) )
// AddStakingContractToPendingTransactions adds the deposit smart contract the genesis block. // AddStakingContractToPendingTransactions adds the deposit smart contract the genesis block.
@ -223,6 +224,10 @@ func (node *Node) AddContractKeyAndAddress(t builtInSC) {
// lottery // lottery
lotteryPriKey, _ := crypto.HexToECDSA(contract_constants.DemoAccounts[0].Private) lotteryPriKey, _ := crypto.HexToECDSA(contract_constants.DemoAccounts[0].Private)
node.DemoContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(lotteryPriKey.PublicKey), uint64(0)) node.DemoContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(lotteryPriKey.PublicKey), uint64(0))
case scPuzzle:
// puzzle
puzzlePriKey, _ := crypto.HexToECDSA(contract_constants.PuzzleAccounts[0].Private)
node.PuzzleContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(puzzlePriKey.PublicKey), uint64(0))
default: default:
utils.GetLogInstance().Error("AddContractKeyAndAddress", "unknown SC", t) utils.GetLogInstance().Error("AddContractKeyAndAddress", "unknown SC", t)
} }

@ -1,6 +1,5 @@
package node package node
// CreateTransactionForEnterMethod creates transaction to call enter method of lottery contract.
import ( import (
"fmt" "fmt"
"math" "math"
@ -23,6 +22,7 @@ const (
Enter = "enter" Enter = "enter"
PickWinner = "pickWinner" PickWinner = "pickWinner"
GetPlayers = "getPlayers" GetPlayers = "getPlayers"
PuzzleFund = 100000000
) )
// AddLotteryContract adds the demo lottery contract the genesis block. // AddLotteryContract adds the demo lottery contract the genesis block.

@ -5,4 +5,6 @@ import "errors"
var ( var (
// ErrLotteryAppFailed is the error when a transaction failed to process lottery app. // ErrLotteryAppFailed is the error when a transaction failed to process lottery app.
ErrLotteryAppFailed = errors.New("Failed to process lottery app transaction") ErrLotteryAppFailed = errors.New("Failed to process lottery app transaction")
// ErrPuzzleInsufficientFund is the error when a user does not have sufficient fund to enter.
ErrPuzzleInsufficientFund = errors.New("You do not have sufficient fund to play")
) )

@ -139,6 +139,10 @@ type Node struct {
DemoContractAddress common.Address DemoContractAddress common.Address
LotteryManagerPrivateKey *ecdsa.PrivateKey LotteryManagerPrivateKey *ecdsa.PrivateKey
// Puzzle account.
PuzzleContractAddress common.Address
PuzzleManagerPrivateKey *ecdsa.PrivateKey
//Node Account //Node Account
AccountKey *ecdsa.PrivateKey AccountKey *ecdsa.PrivateKey
@ -282,9 +286,11 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database, is
// TODO(minhdoan): Think of a better approach to deploy smart contract. // TODO(minhdoan): Think of a better approach to deploy smart contract.
// This is temporary for demo purpose. // This is temporary for demo purpose.
node.AddLotteryContract() node.AddLotteryContract()
node.AddPuzzleContract()
} else { } else {
node.AddContractKeyAndAddress(scStaking) node.AddContractKeyAndAddress(scStaking)
node.AddContractKeyAndAddress(scLottery) node.AddContractKeyAndAddress(scLottery)
node.AddContractKeyAndAddress(scPuzzle)
} }
} }
} }

@ -0,0 +1,146 @@
package node
import (
"fmt"
"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 puzzle.
const (
Play = "play"
Payout = "payout"
)
// OneEther represents 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*10, 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 enter method and add it into pending tx list.
func (node *Node) CreateTransactionForPlayMethod(priKey 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
}
key, err := crypto.HexToECDSA(priKey)
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(OneEther) == -1 {
utils.GetLogInstance().Error("puzzle-play: insufficient fund", "error", err)
return ErrPuzzleInsufficientFund
}
nonce := node.GetNonceOfAddress(address)
tx := types.NewTransaction(
nonce,
toAddress,
0,
OneEther,
params.TxGas*10,
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 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(address string, newLevel int) 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
}
// add params for address payable player, uint8 new_level
// TODO(minh, rj)
bytesData, err := abi.Pack(Payout)
if err != nil {
utils.GetLogInstance().Error("Failed to generate ABI function bytes data", "error", err)
return err
}
key := node.PuzzleManagerPrivateKey
if key == nil {
return fmt.Errorf("PuzzleManagerPrivateKey is nil")
}
nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(key.PublicKey))
Amount := big.NewInt(0)
tx := types.NewTransaction(
nonce,
toAddress,
0,
Amount,
params.TxGas*10000,
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
}

@ -64,7 +64,9 @@ func (node *Node) setupForBeaconLeader() {
// Register client new support service. // Register client new support service.
// TODO(minhdoan): Also consider provide clientsupport/restclientsupport for other shards in the future. // TODO(minhdoan): Also consider provide clientsupport/restclientsupport for other shards in the future.
node.serviceManager.RegisterService(service.RestClientSupport, restclientsupport.New( node.serviceManager.RegisterService(service.RestClientSupport, restclientsupport.New(
node.CreateTransactionForEnterMethod, node.GetResult, node.CreateTransactionForPickWinner, node.CallFaucetContract, node.GetBalanceOfAddress)) node.CreateTransactionForEnterMethod, node.GetResult,
node.CreateTransactionForPickWinner, node.CallFaucetContract, node.GetBalanceOfAddress,
node.CreateTransactionForPlayMethod, node.CreateTransactionForPayoutMethod))
// Register randomness service // Register randomness service
node.serviceManager.RegisterService(service.Randomness, randomness.New(node.DRand)) node.serviceManager.RegisterService(service.Randomness, randomness.New(node.DRand))
// Register explorer service. // Register explorer service.

Loading…
Cancel
Save