// NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. func (s *PublicWhisperAPI) NewFilter(args *NewFilterArgs) (*rpc.HexNumber, error) { if s.w == nil { return nil, whisperOffLineErr } var id int filter := Filter{ To: crypto.ToECDSAPub(common.FromHex(args.To)), From: crypto.ToECDSAPub(common.FromHex(args.From)), Topics: NewFilterTopics(args.Topics...), Fn: func(message *Message) { wmsg := NewWhisperMessage(message) s.messagesMu.RLock() // Only read lock to the filter pool defer s.messagesMu.RUnlock() if s.messages[id] != nil { s.messages[id].insert(wmsg) } }, } id = s.w.Watch(filter) s.messagesMu.Lock() s.messages[id] = newWhisperFilter(id, s.w) s.messagesMu.Unlock() return rpc.NewHexNumber(id), nil }
// Post injects a message into the whisper network for distribution. func (s *PublicWhisperAPI) Post(args *PostArgs) (bool, error) { if s.w == nil { return false, whisperOffLineErr } // construct whisper message with transmission options message := NewMessage(common.FromHex(args.Payload)) options := Options{ To: crypto.ToECDSAPub(common.FromHex(args.To)), TTL: time.Duration(args.TTL) * time.Second, Topics: NewTopics(args.Topics...), } // set sender identity if len(args.From) > 0 { if key := s.w.GetIdentity(crypto.ToECDSAPub(common.FromHex(args.From))); key != nil { options.From = key } else { return false, fmt.Errorf("unknown identity to send from: %s", args.From) } } // Wrap and send the message pow := time.Duration(args.Priority) * time.Millisecond envelope, err := message.Wrap(pow, options) if err != nil { return false, err } return true, s.w.Send(envelope) }
func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { var obj struct { From string `json:"from"` To string `json:"to"` Topics []string `json:"topics"` Payload string `json:"payload"` Priority rpc.HexNumber `json:"priority"` TTL rpc.HexNumber `json:"ttl"` } if err := json.Unmarshal(data, &obj); err != nil { return err } args.From = obj.From args.To = obj.To args.Payload = obj.Payload args.Priority = obj.Priority.Int64() args.TTL = obj.TTL.Int64() // decode topic strings args.Topics = make([][]byte, len(obj.Topics)) for i, topic := range obj.Topics { args.Topics[i] = common.FromHex(topic) } return nil }
// BlockNumber retrieves the current head number of the blockchain. func (api *API) BlockNumber() (uint64, error) { res, err := api.request("eth_blockNumber", nil) if err != nil { return 0, err } var hex string if err := json.Unmarshal(res, &hex); err != nil { return 0, err } return new(big.Int).SetBytes(common.FromHex(hex)).Uint64(), nil }
// Syncing returns the current sync status of the node, or nil if the node is not // currently synchronizing with the network. func (api *API) Syncing() (*SyncStatus, error) { // Execute the request and check if syncing is not running res, err := api.request("eth_syncing", nil) if err != nil { return nil, err } var running bool if err := json.Unmarshal(res, &running); err == nil { return nil, nil } // Sync is running, extract the current status result := make(map[string]string) if err := json.Unmarshal(res, &result); err != nil { return nil, err } return &SyncStatus{ StartingBlock: new(big.Int).SetBytes(common.FromHex(result["startingBlock"])).Uint64(), CurrentBlock: new(big.Int).SetBytes(common.FromHex(result["currentBlock"])).Uint64(), HighestBlock: new(big.Int).SetBytes(common.FromHex(result["highestBlock"])).Uint64(), }, nil }
func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { stateDb, err := state.New(block.Root(), s.chainDb) if err != nil { return "0x", nil, err } stateDb = stateDb.Copy() var from *state.StateObject if args.From == (common.Address{}) { accounts, err := s.am.Accounts() if err != nil || len(accounts) == 0 { from = stateDb.GetOrNewStateObject(common.Address{}) } else { from = stateDb.GetOrNewStateObject(accounts[0].Address) } } else { from = stateDb.GetOrNewStateObject(args.From) } from.SetBalance(common.MaxBig) msg := callmsg{ from: from, to: &args.To, gas: args.Gas.BigInt(), gasPrice: args.GasPrice.BigInt(), value: args.Value.BigInt(), data: common.FromHex(args.Data), } if msg.gas.Cmp(common.Big0) == 0 { msg.gas = big.NewInt(50000000) } if msg.gasPrice.Cmp(common.Big0) == 0 { msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } header := s.bc.CurrentBlock().Header() vmenv := core.NewEnv(stateDb, s.bc, msg, header) gp := new(core.GasPool).AddGas(common.MaxBig) res, gas, err := core.ApplyMessage(vmenv, msg, gp) if len(res) == 0 { // backwards compatability return "0x", gas, err } return common.ToHex(res), gas, err } return "0x", common.Big0, nil }
// GetBlockTime retrieves the block of the given number from the canonical chain. func (api *API) GetBlockTime(num uint64) (time.Time, error) { res, err := api.request("eth_getBlockByNumber", []interface{}{rpc.NewHexNumber(num), true}) if err != nil { return time.Time{}, err } result := make(map[string]json.RawMessage) if err := json.Unmarshal(res, &result); err != nil { return time.Time{}, err } var hex string if err := json.Unmarshal(result["timestamp"], &hex); err != nil { return time.Time{}, err } return time.Unix(new(big.Int).SetBytes(common.FromHex(hex)).Int64(), 0), nil }
// Call forms a transaction from the given arguments and tries to execute it on // a private VM with a copy of the state. Any changes are therefore only temporary // and not part of the actual state. This allows for local execution/queries. func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) { block := be.bc.CurrentBlock() statedb, err := state.New(block.Root(), be.chainDb) if err != nil { return "", "", err } var from *state.StateObject if len(fromStr) == 0 { accounts, err := be.am.Accounts() if err != nil || len(accounts) == 0 { from = statedb.GetOrNewStateObject(common.Address{}) } else { from = statedb.GetOrNewStateObject(accounts[0].Address) } } else { from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr)) } from.SetBalance(common.MaxBig) msg := callmsg{ from: from, gas: common.Big(gasStr), gasPrice: common.Big(gasPriceStr), value: common.Big(valueStr), data: common.FromHex(dataStr), } if len(toStr) > 0 { addr := common.HexToAddress(toStr) msg.to = &addr } if msg.gas.Cmp(big.NewInt(0)) == 0 { msg.gas = big.NewInt(50000000) } if msg.gasPrice.Cmp(big.NewInt(0)) == 0 { msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } header := be.bc.CurrentBlock().Header() vmenv := core.NewEnv(statedb, be.bc, msg, header) gp := new(core.GasPool).AddGas(common.MaxBig) res, gas, err := core.ApplyMessage(vmenv, msg, gp) return common.ToHex(res), gas.String(), err }
// SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. func (s *PublicTransactionPoolAPI) SendRawTransaction(encodedTx string) (string, error) { tx := new(types.Transaction) if err := rlp.DecodeBytes(common.FromHex(encodedTx), tx); err != nil { return "", err } s.txPool.SetLocal(tx) if err := s.txPool.Add(tx); err != nil { return "", err } if tx.To() == nil { from, err := tx.From() if err != nil { return "", err } addr := crypto.CreateAddress(from, tx.Nonce()) glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr) } else { glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To()) } return tx.Hash().Hex(), nil }
// HasIdentity checks if the the whisper node is configured with the private key // of the specified public pair. func (s *PublicWhisperAPI) HasIdentity(identity string) (bool, error) { if s.w == nil { return false, whisperOffLineErr } return s.w.HasIdentity(crypto.ToECDSAPub(common.FromHex(identity))), nil }
// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a // JSON message blob into a WhisperFilterArgs structure. func (args *NewFilterArgs) UnmarshalJSON(b []byte) (err error) { // Unmarshal the JSON message and sanity check var obj struct { To interface{} `json:"to"` From interface{} `json:"from"` Topics interface{} `json:"topics"` } if err := json.Unmarshal(b, &obj); err != nil { return err } // Retrieve the simple data contents of the filter arguments if obj.To == nil { args.To = "" } else { argstr, ok := obj.To.(string) if !ok { return fmt.Errorf("to is not a string") } args.To = argstr } if obj.From == nil { args.From = "" } else { argstr, ok := obj.From.(string) if !ok { return fmt.Errorf("from is not a string") } args.From = argstr } // Construct the nested topic array if obj.Topics != nil { // Make sure we have an actual topic array list, ok := obj.Topics.([]interface{}) if !ok { return fmt.Errorf("topics is not an array") } // Iterate over each topic and handle nil, string or array topics := make([][]string, len(list)) for idx, field := range list { switch value := field.(type) { case nil: topics[idx] = []string{} case string: topics[idx] = []string{value} case []interface{}: topics[idx] = make([]string, len(value)) for i, nested := range value { switch value := nested.(type) { case nil: topics[idx][i] = "" case string: topics[idx][i] = value default: return fmt.Errorf("topic[%d][%d] is not a string", idx, i) } } default: return fmt.Errorf("topic[%d] not a string or array", idx) } } topicsDecoded := make([][][]byte, len(topics)) for i, condition := range topics { topicsDecoded[i] = make([][]byte, len(condition)) for j, topic := range condition { topicsDecoded[i][j] = common.FromHex(topic) } } args.Topics = topicsDecoded } return nil }
// ServeHTTP implements http.Handler, extracting and validating payment headers // contained within the HTTP request. If payment information is accepted, the // request is passed on to the internal service for execution. Otherwise the proxy // short circuits the request and sends back an appropriate error. func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { reqLogger := p.logger.New("request-id", atomic.AddUint32(&p.autoid, 1)) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Expose-Headers", VerificationHeader) // Short circuit CORS pre-flight requests if r.Method == "OPTIONS" { reqLogger.Debug("Allowing CORS pre-flight request") w.Header().Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers")) return } // Allow head requests through for data APIs to query the content size if r.Method == "HEAD" { reqLogger.Debug("Allowing data HEAD request") w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Range") res, err := p.service(r) if err != nil { reqLogger.Error("Failed to process API request", "error", err) http.Error(w, "Failed to execute request", http.StatusInternalServerError) return } defer res.Body.Close() p.forward(w, res) return } // Retrieve the authorization header from the original request authHeader := r.Header.Get(AuthorizationHeader) reqLogger.Debug("Received an API request", "authorization", authHeader) // Ensure that all payment information are present if authHeader == "" { p.fail(w, &verification{Error: "Missing HTTP header: " + AuthorizationHeader}) return } auth := new(authorization) if err := json.Unmarshal([]byte(authHeader), auth); err != nil { p.fail(w, &verification{Error: "Invalid authorization header: " + err.Error()}) return } // Process the request and payment based on the proxy type switch p.kind { case CallProxy: // Make sure the consumer authorized the payment for this call consumer, provider := common.HexToAddress(auth.Consumer), common.HexToAddress(auth.Provider) if !p.verifier.Exists(consumer, provider) { p.fail(w, &verification{Unknown: true, Error: "Non existent API subscription"}) return } nonce := p.verifier.Nonce(consumer, provider).Uint64() if auth.Nonce != nonce { p.fail(w, &verification{Error: "Invalid nonce", Nonce: nonce}) return } valid, funded := p.verifier.Verify(consumer, provider, auth.Nonce, new(big.Int).SetUint64(auth.Amount), common.FromHex(auth.Signature)) if !valid { p.fail(w, &verification{Error: "Invalid authorization signature"}) return } if !funded { p.fail(w, &verification{Error: "Not enough funds available"}) return } price := p.verifier.Price(consumer, provider).Uint64() if prev := p.vault.Fetch(provider, consumer); prev != nil && prev.Amount+price > auth.Amount { p.fail(w, &verification{ Error: "Not enough funds authorized", Authorized: prev.Amount, Proof: prev.Signature, Need: prev.Amount + price, }) return } p.vault.Store(auth) // Execute the API internally and proxy the response reqLogger.Debug("Payment accepted for API invocation") res, err := p.service(r) if err != nil { reqLogger.Error("Failed to process API request", "error", err) http.Error(w, "Failed to execute request", http.StatusInternalServerError) return } defer res.Body.Close() p.forward(w, res) case DataProxy: // Since we're paying by the data, retrieve the amount first res, err := p.service(r) if err != nil { reqLogger.Error("Failed to process API request", "error", err) http.Error(w, "Failed to execute request", http.StatusInternalServerError) return } defer res.Body.Close() // Make sure the user authorized payment for all the requested data data := res.ContentLength if data > 0 /* TODO */ { reqLogger.Debug("Payment accepted for API stream", "data", data) p.forward(w, res) } } }
// WriteGenesisBlock writes the genesis block to the database as block number 0 func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) { contents, err := ioutil.ReadAll(reader) if err != nil { return nil, err } var genesis struct { Nonce string Timestamp string ParentHash string ExtraData string GasLimit string Difficulty string Mixhash string Coinbase string Alloc map[string]struct { Code string Storage map[string]string Balance string } } if err := json.Unmarshal(contents, &genesis); err != nil { return nil, err } // creating with empty hash always works statedb, _ := state.New(common.Hash{}, chainDb) for addr, account := range genesis.Alloc { address := common.HexToAddress(addr) statedb.AddBalance(address, common.String2Big(account.Balance)) statedb.SetCode(address, common.Hex2Bytes(account.Code)) for key, value := range account.Storage { statedb.SetState(address, common.HexToHash(key), common.HexToHash(value)) } } root, stateBatch := statedb.CommitBatch() difficulty := common.String2Big(genesis.Difficulty) block := types.NewBlock(&types.Header{ Nonce: types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()), Time: common.String2Big(genesis.Timestamp), ParentHash: common.HexToHash(genesis.ParentHash), Extra: common.FromHex(genesis.ExtraData), GasLimit: common.String2Big(genesis.GasLimit), Difficulty: difficulty, MixDigest: common.HexToHash(genesis.Mixhash), Coinbase: common.HexToAddress(genesis.Coinbase), Root: root, }, nil, nil, nil) if block := GetBlock(chainDb, block.Hash()); block != nil { glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number") err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) if err != nil { return nil, err } return block, nil } if err := stateBatch.Write(); err != nil { return nil, fmt.Errorf("cannot write state: %v", err) } if err := WriteTd(chainDb, block.Hash(), difficulty); err != nil { return nil, err } if err := WriteBlock(chainDb, block); err != nil { return nil, err } if err := WriteBlockReceipts(chainDb, block.Hash(), nil); err != nil { return nil, err } if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil { return nil, err } if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil { return nil, err } return block, nil }
// 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 }
// Charge will redeem all pending payments made to this provider since startup. func (v *accountVault) Charge(charger Charger) { v.lock.RLock() for _, auth := range v.pends { tx, err := charger.Charge(common.HexToAddress(auth.Consumer), common.HexToAddress(auth.Provider), auth.Nonce, new(big.Int).SetUint64(auth.Amount), common.FromHex(auth.Signature)) if err != nil { log15.Error("Failed to charge payment", "authorization", auth, "error", err) } else { log15.Info("Payment charged", "tx", "http://testnet.etherscan.io/tx/"+tx.Hex()) } } v.lock.RUnlock() v.lock.Lock() for consumer, auth := range v.auths { if v.pends[consumer] == auth { delete(v.pends, consumer) } } v.lock.Unlock() }
// 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 }
// Sha3 applies the ethereum sha3 implementation on the input. // It assumes the input is hex encoded. func (s *PublicWeb3API) Sha3(input string) string { return common.ToHex(crypto.Sha3(common.FromHex(input))) }
// 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 }