-
Notifications
You must be signed in to change notification settings - Fork 20.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RPC API: get receipts by block number #19721
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -168,15 +168,24 @@ var ( | |
testBalance = big.NewInt(2e10) | ||
) | ||
|
||
func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { | ||
// Generate test chain. | ||
genesis, blocks := generateTestChain() | ||
func newTestBackend(t *testing.T, withTx bool) (*node.Node, []*types.Block) { | ||
var ( | ||
genesis *core.Genesis | ||
blocks []*types.Block | ||
) | ||
|
||
// Generate test chain | ||
if withTx { | ||
genesis, blocks = generateTestChainWithTx(t) | ||
} else { | ||
genesis, blocks = generateTestChain() | ||
} | ||
|
||
// Start Ethereum service. | ||
var ethservice *eth.Ethereum | ||
n, err := node.New(&node.Config{}) | ||
n.Register(func(ctx *node.ServiceContext) (node.Service, error) { | ||
config := ð.Config{Genesis: genesis} | ||
config := ð.Config{Genesis: genesis, NoPrefetch: true} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. without this parameter it produces |
||
config.Ethash.PowMode = ethash.ModeFake | ||
ethservice, err = eth.New(ctx, config) | ||
return ethservice, err | ||
|
@@ -212,8 +221,47 @@ func generateTestChain() (*core.Genesis, []*types.Block) { | |
return genesis, blocks | ||
} | ||
|
||
func generateTestChainWithTx(t *testing.T) (*core.Genesis, []*types.Block) { | ||
db := rawdb.NewMemoryDatabase() | ||
config := params.AllEthashProtocolChanges | ||
signer := types.NewEIP155Signer(config.ChainID) | ||
genesis := &core.Genesis{ | ||
Config: config, | ||
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, | ||
ExtraData: []byte("test genesis"), | ||
Timestamp: 9000, | ||
} | ||
generate := func(i int, g *core.BlockGen) { | ||
g.OffsetTime(5) | ||
g.SetExtra([]byte("test")) | ||
|
||
switch i { | ||
case 0: | ||
tx, err := types.SignTx(types.NewTransaction(g.TxNonce(testAddr), common.HexToAddress("0x1"), big.NewInt(1), 21000, big.NewInt(1), nil), signer, testKey) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
g.AddTx(tx) | ||
case 1: | ||
tx, err := types.SignTx(types.NewTransaction(g.TxNonce(testAddr), common.HexToAddress("0x2"), big.NewInt(2), 21000, big.NewInt(1), nil), signer, testKey) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
g.AddTx(tx) | ||
} | ||
} | ||
gblock := genesis.ToBlock(db) | ||
engine := ethash.NewFaker() | ||
blocks, _ := core.GenerateChain(config, gblock, engine, db, 2, generate) | ||
blocks = append([]*types.Block{gblock}, blocks...) | ||
|
||
return genesis, blocks | ||
} | ||
|
||
func TestHeader(t *testing.T) { | ||
backend, chain := newTestBackend(t) | ||
backend, chain := newTestBackend(t, false) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
@@ -257,7 +305,7 @@ func TestHeader(t *testing.T) { | |
} | ||
|
||
func TestBalanceAt(t *testing.T) { | ||
backend, _ := newTestBackend(t) | ||
backend, _ := newTestBackend(t, false) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
@@ -303,7 +351,7 @@ func TestBalanceAt(t *testing.T) { | |
} | ||
|
||
func TestTransactionInBlockInterrupted(t *testing.T) { | ||
backend, _ := newTestBackend(t) | ||
backend, _ := newTestBackend(t, false) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
@@ -320,8 +368,51 @@ func TestTransactionInBlockInterrupted(t *testing.T) { | |
} | ||
} | ||
|
||
func TestTransactionInBlock(t *testing.T) { | ||
backend, blocks := newTestBackend(t, true) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
||
ec := NewClient(client) | ||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) | ||
defer cancel() | ||
|
||
tx, err := ec.TransactionInBlock(ctx, blocks[1].Hash(), 0) | ||
if err != nil { | ||
t.Fatalf("TransactionInBlock error = %q", err) | ||
} | ||
if tx == nil { | ||
t.Fatal("transaction should not be nil") | ||
} | ||
} | ||
|
||
func TestBlockReceipts(t *testing.T) { | ||
backend, blocks := newTestBackend(t, true) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
||
ec := NewClient(client) | ||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) | ||
defer cancel() | ||
|
||
receipts, err := ec.BlockReceipts(ctx, big.NewInt(1)) | ||
if err != nil { | ||
t.Fatalf("BlockReceipts error = %q", err) | ||
} | ||
|
||
if len(receipts) == 0 { | ||
t.Fatal("receipts should not be 0 len") | ||
} | ||
|
||
if receipts[0].BlockHash != blocks[1].Hash() { | ||
t.Fatalf("BlockReceipts block hash mismatch, got %v, want %v", receipts[0].BlockHash, blocks[1].Hash()) | ||
} | ||
} | ||
|
||
func TestChainID(t *testing.T) { | ||
backend, _ := newTestBackend(t) | ||
backend, _ := newTestBackend(t, false) | ||
client, _ := backend.Attach() | ||
defer backend.Stop() | ||
defer client.Close() | ||
|
@@ -333,5 +424,6 @@ func TestChainID(t *testing.T) { | |
} | ||
if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 { | ||
t.Fatalf("ChainID returned wrong number: %+v", id) | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1246,6 +1246,71 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha | |
return fields, nil | ||
} | ||
|
||
// GetBlockReceipts returns the block receipts for the given block number. | ||
func (s *PublicTransactionPoolAPI) GetBlockReceipts(ctx context.Context, blockNr rpc.BlockNumber) ([]map[string]interface{}, error) { | ||
block, err := s.b.BlockByNumber(ctx, blockNr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if block == nil { | ||
return nil, nil | ||
} | ||
|
||
txs := block.Transactions() | ||
|
||
receipts, err := s.b.GetReceipts(ctx, block.Hash()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(receipts) != len(txs) { | ||
return nil, fmt.Errorf("receipt and transaction count mismatch") | ||
} | ||
|
||
result := make([]map[string]interface{}, 0, len(receipts)) | ||
|
||
for index, receipt := range receipts { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. receipt.TransactionIndex could stand for index, so |
||
tx := txs[index] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Directly using index of receipts to look for corresponding
|
||
var signer types.Signer = types.FrontierSigner{} | ||
if tx.Protected() { | ||
signer = types.NewEIP155Signer(tx.ChainId()) | ||
} | ||
from, _ := types.Sender(signer, tx) | ||
|
||
fields := map[string]interface{}{ | ||
"blockHash": block.Hash(), | ||
"blockNumber": hexutil.Uint64(blockNr), | ||
"transactionHash": receipt.TxHash, | ||
"transactionIndex": hexutil.Uint64(index), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest to replace |
||
"from": from, | ||
"to": tx.To(), | ||
"gasUsed": hexutil.Uint64(receipt.GasUsed), | ||
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), | ||
"contractAddress": nil, | ||
"logs": receipt.Logs, | ||
"logsBloom": receipt.Bloom, | ||
} | ||
|
||
// Assign receipt status or post state. | ||
if len(receipt.PostState) > 0 { | ||
fields["root"] = hexutil.Bytes(receipt.PostState) | ||
} else { | ||
fields["status"] = hexutil.Uint(receipt.Status) | ||
} | ||
if receipt.Logs == nil { | ||
fields["logs"] = [][]*types.Log{} | ||
} | ||
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation | ||
if receipt.ContractAddress != (common.Address{}) { | ||
fields["contractAddress"] = receipt.ContractAddress | ||
} | ||
|
||
result = append(result, fields) | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
// sign is a helper function that signs a transaction with the private key of the given address. | ||
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { | ||
// Look up the wallet containing the requested signer | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that both
web3ext.go
andweb3.js
need to be modified to bind"eth_getBlockReceipts"
and"GetBlockReceipts"
, and expose"eth_getBlockReceipts"
.