ethclient, ethereum: add NotFound, split transactions out of ChainReader

ethclient now returns ethereum.NotFound if the server returns null and
no error while accessing blockchain data.

The light client cannot provide arbitrary transactions. The change to
split transaction access into its own interface emphasizes that
transactions should not be relied on and recommends use of logs.
This commit is contained in:
Felix Lange
2016-11-29 15:54:06 +01:00
parent fa0cc27400
commit 3bc0fe1ee3
4 changed files with 67 additions and 23 deletions

View File

@ -81,6 +81,8 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
err := ec.c.CallContext(ctx, &raw, method, args...)
if err != nil {
return nil, err
} else if len(raw) == 0 {
return nil, ethereum.NotFound
}
// Decode header and transactions.
var head *types.Header
@ -135,6 +137,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
var head *types.Header
err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false)
if err == nil && head == nil {
err = ethereum.NotFound
}
return head, err
}
@ -143,19 +148,31 @@ func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.He
func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
var head *types.Header
err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false)
if err == nil && head == nil {
err = ethereum.NotFound
}
return head, err
}
// TransactionByHash returns the transaction with the given hash.
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, error) {
var tx *types.Transaction
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
if err == nil {
if _, r, _ := tx.RawSignatureValues(); r == nil {
return nil, fmt.Errorf("server returned transaction without signature")
}
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
var raw json.RawMessage
err = ec.c.CallContext(ctx, &raw, "eth_getTransactionByHash", hash)
if err != nil {
return nil, false, err
} else if len(raw) == 0 {
return nil, false, ethereum.NotFound
}
return tx, err
if err := json.Unmarshal(raw, tx); err != nil {
return nil, false, err
} else if _, r, _ := tx.RawSignatureValues(); r == nil {
return nil, false, fmt.Errorf("server returned transaction without signature")
}
var block struct{ BlockHash *common.Hash }
if err := json.Unmarshal(raw, &block); err != nil {
return nil, false, err
}
return tx, block.BlockHash == nil, nil
}
// TransactionCount returns the total number of transactions in the given block.
@ -170,11 +187,9 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
var tx *types.Transaction
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index)
if err == nil {
var signer types.Signer = types.HomesteadSigner{}
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
if _, r, _ := types.SignatureValues(signer, tx); r == nil {
if tx == nil {
return nil, ethereum.NotFound
} else if _, r, _ := tx.RawSignatureValues(); r == nil {
return nil, fmt.Errorf("server returned transaction without signature")
}
}
@ -186,8 +201,12 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
var r *types.Receipt
err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash)
if err == nil && r != nil && len(r.PostState) == 0 {
return nil, fmt.Errorf("server returned receipt without post state")
if err == nil {
if r == nil {
return nil, ethereum.NotFound
} else if len(r.PostState) == 0 {
return nil, fmt.Errorf("server returned receipt without post state")
}
}
return r, err
}