package chain
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/console"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/eth"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
// "github.com/ethereum/go-ethereum/accounts/abi"
|
|
)
|
|
|
|
type Node interface {
|
|
Init() error
|
|
Start()
|
|
LinkBatch([]byte) error
|
|
}
|
|
|
|
type EthNodeHandle struct {
|
|
n *node.Node
|
|
s *eth.Ethereum
|
|
c *eth.Config
|
|
k *keystore.KeyStore
|
|
}
|
|
|
|
func Init() (Node, error) {
|
|
e := new(EthNodeHandle)
|
|
err := e.Init()
|
|
return e, err
|
|
}
|
|
|
|
func (e *EthNodeHandle) Init() error {
|
|
|
|
nodeConfig := node.DefaultConfig
|
|
nodeConfig.IPCPath = "run/eth/ipc"
|
|
nodeConfig.DataDir = "run/eth/data"
|
|
|
|
//might also make sense to use staticnodes instead of bootstrap
|
|
var urls = []string{
|
|
"enode://e97bbd1b66c91a3e042703ec1a9af9361e7c84d892632cfa995bad96f3fa630b7048c8194e2bbc8984a612db7f5f8ca29be5d807d8abe5db86d5505b62eaa382@51.15.114.224:30303",
|
|
"enode://480fbf14bab92f6203140403f5a1d4b4a8af143b4bc2c48d7f09fd3a294d08955611c362064ea01681663e42638440a888c326977e178a35295f5c1ca99dfb0f@51.15.71.154:30303",
|
|
"enode://d6165c23b1d4415f845922b6589fcf19c62e07555c867848a890978993230dad039c248975578216b69a9f7a8fbc2b58db4817bd693f464a6aa45af90964b1e2@51.15.102.251:30303",
|
|
"enode://3722cb9af22c61294fe6a0a7beb1db176ef456eb4cab1f6551cefb44e253450342de6459bcf576bd97797cf0df9e818db3d048532f3068351ed1bacaa6ec0d20@51.15.89.137:30303",
|
|
}
|
|
nodeConfig.P2P.BootstrapNodes = make([]*enode.Node, 0, len(urls))
|
|
for _, url := range urls {
|
|
if url != "" {
|
|
node, err := enode.ParseV4(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nodeConfig.P2P.BootstrapNodes = append(nodeConfig.P2P.BootstrapNodes, node)
|
|
}
|
|
}
|
|
n, err := node.New(&nodeConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ethConfig := eth.DefaultConfig
|
|
ethConfig.NetworkId = 1714
|
|
//ethConfig.SyncMode = downloader.LightSync
|
|
var genesisJson *os.File
|
|
genesisJson, err = os.Open("genesis.json")
|
|
genesisBytes, _ := ioutil.ReadAll(genesisJson)
|
|
g := new(core.Genesis)
|
|
g.UnmarshalJSON(genesisBytes)
|
|
ethConfig.Genesis = g
|
|
|
|
ks := keystore.NewKeyStore("run/eth/keystore", keystore.StandardScryptN, keystore.StandardScryptP)
|
|
|
|
e.n = n
|
|
e.c = ðConfig
|
|
e.k = ks
|
|
|
|
return nil
|
|
}
|
|
|
|
func (e *EthNodeHandle) Start() {
|
|
utils.RegisterEthService(e.n, e.c)
|
|
utils.StartNode(e.n)
|
|
if len(e.k.Accounts()) < 1 {
|
|
e.createAccount()
|
|
} else {
|
|
phrase := getPassPhrase("please provide primary account passphrase", false)
|
|
e.k.TimedUnlock(e.k.Accounts()[0], phrase, time.Duration(0))
|
|
}
|
|
}
|
|
|
|
func (e *EthNodeHandle) LinkBatch(data []byte) error {
|
|
// contractAddr := "0x3e4FfefF898580eC8132A97A91543c8fdeF1210E"
|
|
bigWalletAddr := "0x781b6544b1a73c6d779eb23c7369cf8039640793"
|
|
var gasLimit uint64
|
|
gasLimit = 8000000
|
|
return e.sendContractTx(bigWalletAddr, gasLimit, data)
|
|
}
|
|
|
|
// might be worthwhile to create generic SendTx to call contracttx, deploytx, etc
|
|
|
|
func (e *EthNodeHandle) sendContractTx(addr string, limit uint64, data []byte) error {
|
|
|
|
fmt.Println(e.n)
|
|
client, err := ethclient.Dial(e.n.IPCEndpoint())
|
|
fmt.Println("Got IPC Endpoint:" + e.n.IPCEndpoint())
|
|
deadline := time.Now().Add(1000 * time.Millisecond)
|
|
ctx, cancel := context.WithDeadline(context.TODO(), deadline)
|
|
defer cancel()
|
|
fmt.Println("context created")
|
|
|
|
accounts := e.k.Accounts()
|
|
fmt.Println("Listing accounts")
|
|
for i, a := range accounts {
|
|
fmt.Printf("Found account %d %s\n", i, a.Address.String())
|
|
}
|
|
acc := accounts[0]
|
|
sendAddr := acc.Address
|
|
nonce, _ := client.NonceAt(ctx, sendAddr, nil)
|
|
if err != nil {
|
|
fmt.Println("error")
|
|
return err
|
|
}
|
|
//create tx
|
|
fmt.Println("creating tx")
|
|
price, _ := client.SuggestGasPrice(ctx)
|
|
fmt.Println(price)
|
|
var empty []byte
|
|
tx := types.NewTransaction(nonce, common.HexToAddress(addr), big.NewInt(1), limit, price, empty)
|
|
signedTx, err := e.k.SignTx(acc, tx, big.NewInt(int64(e.c.NetworkId)))
|
|
if err != nil {
|
|
fmt.Printf("Signing error: %s", err)
|
|
}
|
|
//create ctx
|
|
err = client.SendTransaction(ctx, signedTx)
|
|
fmt.Println(err)
|
|
//fix return*/
|
|
return err
|
|
}
|
|
|
|
func (e *EthNodeHandle) createAccount() error {
|
|
phrase := getPassPhrase("Your new account will be locked with a passphrase. Please give a passphrase. Do not forget it!.", true)
|
|
acc, err := e.k.NewAccount(phrase)
|
|
|
|
if err != nil {
|
|
utils.Fatalf("Failed to create account: %v", err)
|
|
}
|
|
fmt.Printf("Address: {%x}\n", acc.Address)
|
|
e.k.TimedUnlock(e.k.Accounts()[0], phrase, time.Duration(0))
|
|
|
|
return nil
|
|
}
|
|
|
|
func getPassPhrase(prompt string, confirmation bool) string {
|
|
// Otherwise prompt the user for the password
|
|
if prompt != "" {
|
|
fmt.Println(prompt)
|
|
}
|
|
phrase, err := console.Stdin.PromptPassword("Passphrase: ")
|
|
if err != nil {
|
|
utils.Fatalf("Failed to read passphrase: %v", err)
|
|
}
|
|
if confirmation {
|
|
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
|
if err != nil {
|
|
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
|
}
|
|
if phrase != confirm {
|
|
utils.Fatalf("Passphrases do not match")
|
|
}
|
|
}
|
|
return phrase
|
|
}
|