コード例 #1
0
ファイル: contract.go プロジェクト: efaysal/etherapis
// Start Go API. Not important for this version
func (c *Channels) NewChannel(key *ecdsa.PrivateKey, to common.Address, amount, price *big.Int, cb func(*Channel)) (*types.Transaction, error) {
	from := crypto.PubkeyToAddress(key.PublicKey)

	data, err := c.abi.Pack("createChannel", to, price)
	if err != nil {
		return nil, err
	}

	statedb, err := c.blockchain.State()
	if err != nil {
		return nil, err
	}

	transaction, err := types.NewTransaction(statedb.GetNonce(from), contractAddress, amount, big.NewInt(250000), big.NewInt(50000000000), data).SignECDSA(key)
	if err != nil {
		return nil, err
	}

	evId := c.abi.Events["NewChannel"].Id()
	filter := filters.New(c.db)
	filter.SetAddresses([]common.Address{contractAddress})
	filter.SetTopics([][]common.Hash{ // TODO refactor, helper
		[]common.Hash{evId},
		[]common.Hash{from.Hash()},
		[]common.Hash{to.Hash()},
	})
	filter.SetBeginBlock(0)
	filter.SetEndBlock(-1)
	filter.LogsCallback = func(logs vm.Logs) {
		// tere should really be only one log. TODO this part
		log := logs[0]

		// TODO: do to and from validation here
		/*
			from := log.Topics[1]
			to := log.Topics[2]
		*/
		channelId := common.BytesToHash(log.Data[0:31])
		nonce := common.BytesToBig(log.Data[31:])

		c.channelMu.Lock()
		defer c.channelMu.Unlock()

		channel, exist := c.channels[channelId]
		if !exist {
			channel = NewChannel(c, channelId, from, to, nonce)
			c.channels[channelId] = channel
		}
		cb(channel)
	}

	c.filters.Add(filter)

	return transaction, nil
}
コード例 #2
0
ファイル: contract.go プロジェクト: efaysal/etherapis
// exec is the executer function callback for the abi `Call` method.
func (c *Channels) exec(input []byte) (out []byte) {
	header := c.blockchain.CurrentHeader()
	gasLimit := big.NewInt(3141592)
	statedb, _ := c.blockchain.State()

	var addr common.Address
	tx, _ := types.NewTransaction(statedb.GetNonce(addr), contractAddress, new(big.Int), gasLimit, new(big.Int), input).SignECDSA(c.callKey)
	env := core.NewEnv(statedb, c.blockchain, tx, header)
	ret, _, _ := core.ApplyMessage(env, tx, new(core.GasPool).AddGas(gasLimit))

	return ret
}
コード例 #3
0
ファイル: api.go プロジェクト: efaysal/etherapis
func (tx *Tx) UnmarshalJSON(b []byte) (err error) {
	req := struct {
		To       common.Address `json:"to"`
		From     common.Address `json:"from"`
		Nonce    *rpc.HexNumber `json:"nonce"`
		Value    *rpc.HexNumber `json:"value"`
		Data     string         `json:"data"`
		GasLimit *rpc.HexNumber `json:"gas"`
		GasPrice *rpc.HexNumber `json:"gasPrice"`
		Hash     common.Hash    `json:"hash"`
	}{}

	if err := json.Unmarshal(b, &req); err != nil {
		return err
	}

	contractCreation := (req.To == (common.Address{}))

	tx.To = &req.To
	tx.From = req.From
	tx.Nonce = req.Nonce
	tx.Value = req.Value
	tx.Data = req.Data
	tx.GasLimit = req.GasLimit
	tx.GasPrice = req.GasPrice
	tx.Hash = req.Hash

	data := common.Hex2Bytes(tx.Data)

	if tx.Nonce == nil {
		return fmt.Errorf("need nonce")
	}
	if tx.Value == nil {
		tx.Value = rpc.NewHexNumber(0)
	}
	if tx.GasLimit == nil {
		tx.GasLimit = rpc.NewHexNumber(0)
	}
	if tx.GasPrice == nil {
		tx.GasPrice = rpc.NewHexNumber(defaultGasPrice)
	}

	if contractCreation {
		tx.tx = types.NewContractCreation(tx.Nonce.Uint64(), tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data)
	} else {
		if tx.To == nil {
			return fmt.Errorf("need to address")
		}
		tx.tx = types.NewTransaction(tx.Nonce.Uint64(), *tx.To, tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data)
	}

	return nil
}
コード例 #4
0
ファイル: api.go プロジェクト: efaysal/etherapis
// SendTransaction will create a transaction for the given transaction argument, sign it and submit it to the
// transaction pool.
func (s *PublicTransactionPoolAPI) SendTransaction(args SendTxArgs) (common.Hash, error) {
	if args.Gas == nil {
		args.Gas = rpc.NewHexNumber(defaultGas)
	}
	if args.GasPrice == nil {
		args.GasPrice = rpc.NewHexNumber(defaultGasPrice)
	}
	if args.Value == nil {
		args.Value = rpc.NewHexNumber(0)
	}

	s.txMu.Lock()
	defer s.txMu.Unlock()

	if args.Nonce == nil {
		args.Nonce = rpc.NewHexNumber(s.txPool.State().GetNonce(args.From))
	}

	var tx *types.Transaction
	contractCreation := (args.To == common.Address{})

	if contractCreation {
		tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
	} else {
		tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
	}

	signedTx, err := s.sign(args.From, tx)
	if err != nil {
		return common.Hash{}, err
	}

	s.txPool.SetLocal(signedTx)
	if err := s.txPool.Add(signedTx); err != nil {
		return common.Hash{}, nil
	}

	if contractCreation {
		addr := crypto.CreateAddress(args.From, args.Nonce.Uint64())
		glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
	} else {
		glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex())
	}

	return signedTx.Hash(), nil
}
コード例 #5
0
ファイル: contract.go プロジェクト: efaysal/etherapis
// Claim redeems a given signature using the canonical channel. It creates an
// Ethereum transaction and submits it to the Ethereum network.
//
// Chaim returns the unsigned transaction and an error if it failed.
func (c *Channels) Claim(signer common.Address, from, to common.Address, nonce uint64, amount *big.Int, sig []byte) (*types.Transaction, error) {
	if len(sig) != 65 {
		return nil, fmt.Errorf("Invalid signature. Signature requires to be 65 bytes")
	}

	channelId := c.ChannelId(from, to)
	signature := bytesToSignature(sig)

	txData, err := c.abi.Pack("claim", channelId, nonce, amount, signature.v, signature.r, signature.s)
	if err != nil {
		return nil, err
	}

	statedb, _ := c.blockchain.State()
	gasPrice := big.NewInt(50000000000)
	gasLimit := big.NewInt(250000)
	tx := types.NewTransaction(statedb.GetNonce(signer), contractAddress, new(big.Int), gasLimit, gasPrice, txData)
	return tx, nil
}
コード例 #6
0
ファイル: api.go プロジェクト: efaysal/etherapis
// SignTransaction will sign the given transaction with the from account.
// The node needs to have the private key of the account corresponding with
// the given from address and it needs to be unlocked.
func (s *PublicTransactionPoolAPI) SignTransaction(args *SignTransactionArgs) (*SignTransactionResult, error) {
	if args.Gas == nil {
		args.Gas = rpc.NewHexNumber(defaultGas)
	}
	if args.GasPrice == nil {
		args.GasPrice = rpc.NewHexNumber(defaultGasPrice)
	}
	if args.Value == nil {
		args.Value = rpc.NewHexNumber(0)
	}

	s.txMu.Lock()
	defer s.txMu.Unlock()

	if args.Nonce == nil {
		args.Nonce = rpc.NewHexNumber(s.txPool.State().GetNonce(args.From))
	}

	var tx *types.Transaction
	contractCreation := (args.To == common.Address{})

	if contractCreation {
		tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
	} else {
		tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
	}

	signedTx, err := s.sign(args.From, tx)
	if err != nil {
		return nil, err
	}

	data, err := rlp.EncodeToBytes(signedTx)
	if err != nil {
		return nil, err
	}

	return &SignTransactionResult{"0x" + common.Bytes2Hex(data), newTx(tx)}, nil
}
コード例 #7
0
ファイル: api.go プロジェクト: efaysal/etherapis
// Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the
// pool and reinsert it with the new gas price and limit.
func (s *PublicTransactionPoolAPI) Resend(tx *Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {

	pending := s.txPool.GetTransactions()
	for _, p := range pending {
		if pFrom, err := p.From(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() {
			if gasPrice == nil {
				gasPrice = rpc.NewHexNumber(tx.tx.GasPrice())
			}
			if gasLimit == nil {
				gasLimit = rpc.NewHexNumber(tx.tx.Gas())
			}

			var newTx *types.Transaction
			contractCreation := (*tx.tx.To() == common.Address{})
			if contractCreation {
				newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data())
			} else {
				newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data())
			}

			signedTx, err := s.sign(tx.From, newTx)
			if err != nil {
				return common.Hash{}, err
			}

			s.txPool.RemoveTx(tx.Hash)
			if err = s.txPool.Add(signedTx); err != nil {
				return common.Hash{}, err
			}

			return signedTx.Hash(), nil
		}
	}

	return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash)
}
コード例 #8
0
ファイル: main.go プロジェクト: efaysal/etherapis
func main() {
	// Parse and handle the command line flags
	flag.Parse()

	log15.Root().SetHandler(log15.LvlFilterHandler(log15.Lvl(*loglevelFlag), log15.StderrHandler))

	datadir := *datadirFlag
	if datadir == "" {
		datadir = filepath.Join(os.Getenv("HOME"), ".etherapis")
	}
	if err := os.MkdirAll(datadir, 0700); err != nil {
		log15.Crit("Failed to create data directory: %v", err)
		return
	}
	// Assemble and start the Ethereum client
	log15.Info("Booting Ethereum client...")
	client, err := geth.New(datadir, geth.TestNet)
	if err != nil {
		log15.Crit("Failed to create Ethereum client", "error", err)
		return
	}
	if err := client.Start(); err != nil {
		log15.Crit("Failed to start Ethereum client", "error", err)
		return
	}
	api, err := client.Attach()
	if err != nil {
		log15.Crit("Failed to attach to node", "error", err)
		return
	}
	// Wait for network connectivity and monitor synchronization
	log15.Info("Searching for network peers...")
	server := client.Stack().Server()
	for len(server.Peers()) == 0 {
		time.Sleep(100 * time.Millisecond)
	}
	go monitorSync(api)

	// Make sure we're at least semi recent on the chain before continuing
	waitSync(*syncFlag, api)

	var eth *eth.Ethereum
	err = client.Stack().Service(&eth)
	if err != nil {
		log15.Crit("Failed to fetch eth service", "error", err)
		return
	}
	contract, err := channels.Fetch(eth.ChainDb(), eth.EventMux(), eth.BlockChain())
	if err != nil {
		log15.Crit("Failed to get contract", "error", err)
		return
	}
	// Depending on the flags, execute different things
	switch {
	case *signFlag != "":
		var message struct {
			Provider string
			Nonce    uint64
			Amount   uint64
		}
		if err := json.Unmarshal([]byte(*signFlag), &message); err != nil {
			log15.Crit("Failed to decode data", "error", err)
			return
		}
		fmt.Println(message)
		accounts, err := eth.AccountManager().Accounts()
		if err != nil {
			log15.Crit("Failed retrieving accounts", "err", err)
		}
		if len(accounts) == 0 {
			log15.Crit("Signing data requires at least one account", "len", len(accounts))
			return
		}
		account := accounts[0]

		from := account.Address
		to := common.HexToAddress(message.Provider)

		hash := contract.Call("getHash", from, to, message.Nonce, message.Amount).([]byte)
		log15.Info("getting hash", "hash", common.ToHex(hash))

		eth.AccountManager().Unlock(from, "")
		sig, err := eth.AccountManager().Sign(account, hash)
		if err != nil {
			log15.Crit("signing vailed", "err", err)
			return
		}
		log15.Info("generated signature", "sig", common.ToHex(sig))

		return

	case *importFlag != "":
		// Account import, parse the provided .json file and ensure it's proper
		manager := eth.AccountManager()
		account, err := manager.Import(*importFlag, "")
		if err != nil {
			log15.Crit("Failed to import specified account", "path", *importFlag, "error", err)
			return
		}
		state, _ := eth.BlockChain().State()
		log15.Info("Account successfully imported", "account", fmt.Sprintf("0x%x", account.Address), "balance", state.GetBalance(account.Address))
		return

	case *accountsFlag:
		// Account listing requested, print all accounts and balances
		accounts, err := eth.AccountManager().Accounts()
		if err != nil || len(accounts) == 0 {
			log15.Crit("Failed to retrieve account", "accounts", len(accounts), "error", err)
			return
		}
		state, _ := eth.BlockChain().State()
		for i, account := range accounts {
			balance := float64(new(big.Int).Div(state.GetBalance(account.Address), common.Finney).Int64()) / 1000
			fmt.Printf("Account #%d: %f ether (http://testnet.etherscan.io/address/0x%x)\n", i, balance, account.Address)
		}
		return

	case *accGenFlag > 0:
		// We're generating and dumping demo accounts
		var nonce uint64
		var bank accounts.Account

		if *accLiveFlag {
			// If we want to fund generated accounts, make sure we can
			accounts, err := eth.AccountManager().Accounts()
			if err != nil || len(accounts) == 0 {
				log15.Crit("Failed to retrieve funding account", "accounts", len(accounts), "error", err)
				return
			}
			bank = accounts[0]
			if err := eth.AccountManager().Unlock(bank.Address, "gophergala"); err != nil {
				log15.Crit("Failed to unlock funding account", "account", fmt.Sprintf("0x%x", bank.Address), "error", err)
				return
			}
			state, _ := eth.BlockChain().State()
			nonce = state.GetNonce(bank.Address)

			log15.Info("Funding demo accounts with", "bank", fmt.Sprintf("0x%x", bank.Address), "nonce", nonce)
		}
		// Start generating the actual accounts
		log15.Info("Generating demo accounts", "count", *accGenFlag)
		for i := 0; i < *accGenFlag; i++ {
			// Generate a new account
			account, err := eth.AccountManager().NewAccount("pass")
			if err != nil {
				log15.Crit("Failed to generate new account", "error", err)
				return
			}
			// Export it's private key
			keyPath := fmt.Sprintf("0x%x.key", account.Address)
			if err := eth.AccountManager().Export(keyPath, account.Address, "pass"); err != nil {
				log15.Crit("Failed to export account", "account", fmt.Sprintf("0x%x", account.Address), "error", err)
				return
			}
			// Clean up so it doesn't clutter out accounts
			if err := eth.AccountManager().DeleteAccount(account.Address, "pass"); err != nil {
				log15.Crit("Failed to delete account", "account", fmt.Sprintf("0x%x", account.Address), "error", err)
				return
			}
			// If we're just testing, stop here
			if !*accLiveFlag {
				log15.Info("Account generated and exported", "path", keyPath)
				continue
			}
			// Oh boy, live accounts, send some ether to it and upload to the faucet
			allowance := new(big.Int).Mul(big.NewInt(10), common.Ether)
			price := new(big.Int).Mul(big.NewInt(50), common.Shannon)

			tx := types.NewTransaction(nonce, account.Address, allowance, big.NewInt(21000), price, nil)
			sig, err := eth.AccountManager().Sign(bank, tx.SigHash().Bytes())
			if err != nil {
				log15.Crit("Failed to sign funding transaction", "error", err)
				return
			}
			stx, err := tx.WithSignature(sig)
			if err != nil {
				log15.Crit("Failed to assemble funding transaction", "error", err)
				return
			}
			if err := eth.TxPool().Add(stx); err != nil {
				log15.Crit("Failed to execute transfer", "error", err)
				return
			}
			nonce++
			log15.Info("Account successfully funded", "account", fmt.Sprintf("0x%x", account.Address))

			// Upload the account to the faucet server
			key, err := ioutil.ReadFile(keyPath)
			if err != nil {
				log15.Crit("Failed to load private key", "error", err)
				return
			}
			res, err := http.Get("https://etherapis.appspot.com/faucet/fund?key=" + string(key))
			if err != nil {
				log15.Crit("Failed to upload private key to faucet", "error", err)
				return
			}
			res.Body.Close()

			log15.Info("Account uploaded to faucet", "account", fmt.Sprintf("0x%x", account.Address))
			os.Remove(keyPath)
		}
		// Just wait a bit to ensure transactions get propagated into the network
		log15.Info("Sleeping to ensure transaction propagation")
		time.Sleep(10 * time.Second)
		return

	case len(*queryFlag) > 0:
		// Check whether any of our accounts are subscribed to this particular service
		accounts, err := eth.AccountManager().Accounts()
		if err != nil || len(accounts) == 0 {
			log15.Crit("Failed to retrieve account", "accounts", len(accounts), "error", err)
			return
		}
		provider := common.HexToAddress(*queryFlag)
		log15.Info("Checking subscription status", "service", fmt.Sprintf("0x%x", provider))
		for i, account := range accounts {
			// Check if a subscription exists
			if !contract.Exists(account.Address, provider) {
				fmt.Printf("Account #%d: [0x%x]: not subscribed.\n", i, account.Address)
				continue
			}
			// Retrieve the current balance on the subscription
			ethers := contract.Call("getChannelValue", contract.ChannelId(account.Address, provider)).(*big.Int)
			funds := float64(new(big.Int).Div(ethers, common.Finney).Int64()) / 1000

			fmt.Printf("Account #%d: [0x%x]: subscribed, with %v ether(s) left.\n", i, account.Address, funds)
		}
		return

	case len(*subToFlag) > 0:
		// Subscription requested, make sure all the details are provided
		accounts, err := eth.AccountManager().Accounts()
		if err != nil || len(accounts) < *subAccFlag {
			log15.Crit("Failed to retrieve account", "accounts", len(accounts), "requested", *subAccFlag, "error", err)
			return
		}
		account := accounts[*subAccFlag]

		// Check if a subscription exists
		provider := common.HexToAddress(*subToFlag)
		if contract.Exists(account.Address, provider) {
			log15.Error("Account already subscribed", "index", *subAccFlag, "account", fmt.Sprintf("0x%x", account.Address), "service", fmt.Sprintf("0x%x", provider))
			return
		}
		// Try to subscribe and wait until it completes
		keystore := client.Keystore()
		key, err := keystore.GetKey(account.Address, "")
		if err != nil {
			log15.Crit("Failed to unlock account", "account", fmt.Sprintf("0x%x", account.Address), "error", err)
			return
		}
		amount := new(big.Int).Mul(big.NewInt(int64(1000000000**subFundFlag)), common.Shannon)

		log15.Info("Subscribing to new payment channel", "account", fmt.Sprintf("0x%x", account.Address), "service", fmt.Sprintf("0x%x", provider), "ethers", *subFundFlag)
		pend := make(chan *channels.Channel)
		tx, err := contract.NewChannel(key.PrivateKey, provider, amount, big.NewInt(1), func(sub *channels.Channel) { pend <- sub })
		if err != nil {
			log15.Crit("Failed to create subscription", "error", err)
			return
		}
		if err := eth.TxPool().Add(tx); err != nil {
			log15.Crit("Failed to execute subscription", "error", err)
			return
		}
		log15.Info("Waiting for subscription to be finalized...", "tx", tx)
		log15.Info("Successfully subscribed", "channel", fmt.Sprintf("%x", (<-pend).Id))
		return
	}

	if *testFlag {
		accounts, err := eth.AccountManager().Accounts()
		if err != nil {
			log15.Crit("Failed retrieving accounts", "err", err)
		}
		if len(accounts) < 2 {
			log15.Crit("Test vectors requires at least 2 accounts", "len", len(accounts))
			return
		}

		log15.Info("Attempting channel test vectors...")
		from := accounts[0].Address
		eth.AccountManager().Unlock(from, "")

		to := accounts[0].Address
		log15.Info("making channel name...", "from", from.Hex(), "to", to.Hex(), "ID", contract.ChannelId(from, to).Hex())
		log15.Info("checking existence...", "exists", contract.Exists(from, to))

		amount := big.NewInt(1)
		hash := contract.Call("getHash", from, to, 0, amount).([]byte)
		log15.Info("signing data", "to", to.Hex(), "amount", amount, "hash", common.ToHex(hash))

		sig, err := eth.AccountManager().Sign(accounts[0], hash)
		if err != nil {
			log15.Crit("signing vailed", "err", err)
			return
		}
		log15.Info("verifying signature", "sig", common.ToHex(sig))

		if contract.ValidateSig(from, to, 0, amount, sig) {
			log15.Info("signature was valid and was verified by the EVM")
		} else {
			log15.Crit("signature was invalid")
			return
		}

		log15.Info("verifying payment", "sig", common.ToHex(sig))
		if valid, _ := contract.Verify(from, to, 0, amount, sig); valid {
			log15.Info("payment was valid and was verified by the EVM")
		} else {
			log15.Crit("payment was invalid")
			return
		}

		log15.Info("verifying invalid payment", "nonce", 1)
		if valid, _ := contract.Verify(from, to, 1, amount, sig); valid {
			log15.Crit("payment was valid")
			return
		} else {
			log15.Info("payment was invalid")
		}
	}

	// If we're running a proxy, start processing external requests
	if *proxyFlag != "" {
		// Subscription requested, make sure all the details are provided
		accounts, err := eth.AccountManager().Accounts()
		if err != nil || len(accounts) < *subAccFlag {
			log15.Crit("Failed to retrieve account", "accounts", len(accounts), "requested", *subAccFlag, "error", err)
			return
		}
		account := accounts[*subAccFlag]
		if err := eth.AccountManager().Unlock(account.Address, ""); err != nil {
			log15.Crit("Failed to unlock provider account", "account", fmt.Sprintf("0x%x", account.Address), "error", err)
			return
		}
		log15.Info("Setuping vault...", "owner", account.Address.Hex())

		// Create the payment vault to hold the various authorizations
		vault := proxy.NewVault(NewCharger(account, eth.TxPool(), contract, eth.AccountManager()))
		vault.AutoCharge(*chargeFlag)

		for i, config := range strings.Split(*proxyFlag, ",") {
			// Split the proxy configuration
			parts := strings.Split(config, ":")
			if len(parts) != 3 {
				log15.Crit("Invalid proxy config", "config", config)
				return
			}
			extPort, err := strconv.Atoi(parts[0])
			if err != nil || extPort < 0 || extPort > 65535 {
				log15.Crit("Invalid external port number", "port", parts[0])
				return
			}
			intPort, err := strconv.Atoi(parts[1])
			if err != nil || intPort < 0 || intPort > 65535 {
				log15.Crit("Invalid internal port number", "port", parts[1])
				return
			}
			var kind proxy.ProxyType
			switch strings.ToLower(parts[2]) {
			case "call":
				kind = proxy.CallProxy
			case "data":
				kind = proxy.DataProxy
			default:
				log15.Crit("Unsupported proxy type", "type", parts[2], "allowed", []string{"call", "data"})
				return
			}
			// Create and start the new proxy
			gateway := proxy.New(i, extPort, intPort, kind, contract, vault)
			go func() {
				if err := gateway.Start(); err != nil {
					log15.Crit("Failed to start proxy", "error", err)
					os.Exit(-1)
				}
			}()
		}
		// Wait indefinitely, for now at least
		for {
			time.Sleep(time.Second)
		}
	}
	// Clean up for now
	log15.Info("Terminating Ethereum client...")
	if err := client.Stop(); err != nil {
		log15.Crit("Failed to terminate Ethereum client", "error", err)
		return
	}
}
コード例 #9
0
ファイル: api.go プロジェクト: efaysal/etherapis
// Transact forms a transaction from the given arguments and submits it to the
// transactio pool for execution.
func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
	if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) {
		return "", errors.New("invalid address")
	}

	var (
		from             = common.HexToAddress(fromStr)
		to               = common.HexToAddress(toStr)
		value            = common.Big(valueStr)
		gas              *big.Int
		price            *big.Int
		data             []byte
		contractCreation bool
	)

	if len(gasStr) == 0 {
		gas = big.NewInt(90000)
	} else {
		gas = common.Big(gasStr)
	}

	if len(gasPriceStr) == 0 {
		price = big.NewInt(10000000000000)
	} else {
		price = common.Big(gasPriceStr)
	}

	data = common.FromHex(codeStr)
	if len(toStr) == 0 {
		contractCreation = true
	}

	nonce := be.txPool.State().GetNonce(from)
	if len(nonceStr) != 0 {
		nonce = common.Big(nonceStr).Uint64()
	}

	var tx *types.Transaction
	if contractCreation {
		tx = types.NewContractCreation(nonce, value, gas, price, data)
	} else {
		tx = types.NewTransaction(nonce, to, value, gas, price, data)
	}

	acc := accounts.Account{from}
	signature, err := be.am.Sign(acc, tx.SigHash().Bytes())
	if err != nil {
		return "", err
	}
	signedTx, err := tx.WithSignature(signature)
	if err != nil {
		return "", err
	}

	be.txPool.SetLocal(signedTx)
	if err := be.txPool.Add(signedTx); err != nil {
		return "", nil
	}

	if contractCreation {
		addr := crypto.CreateAddress(from, nonce)
		glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
	} else {
		glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex())
	}

	return signedTx.Hash().Hex(), nil
}