forked from cerc-io/ipld-eth-server
Add receipts (#119)
* Conversion between Geth Receipt and core.Receipt * Add receipt to DB * Insert receipts with transactions * Update Travis CI to use dep for dependencies
This commit is contained in:
@@ -8,11 +8,29 @@ import (
|
||||
|
||||
type InMemory struct {
|
||||
blocks map[int64]core.Block
|
||||
receipts map[string]core.Receipt
|
||||
contracts map[string]core.Contract
|
||||
logs map[string][]core.Log
|
||||
HandleBlockCallCount int
|
||||
}
|
||||
|
||||
func NewInMemory() *InMemory {
|
||||
return &InMemory{
|
||||
HandleBlockCallCount: 0,
|
||||
blocks: make(map[int64]core.Block),
|
||||
receipts: make(map[string]core.Receipt),
|
||||
contracts: make(map[string]core.Contract),
|
||||
logs: make(map[string][]core.Log),
|
||||
}
|
||||
}
|
||||
|
||||
func (repository *InMemory) FindReceipt(txHash string) (core.Receipt, error) {
|
||||
if receipt, ok := repository.receipts[txHash]; ok {
|
||||
return receipt, nil
|
||||
}
|
||||
return core.Receipt{}, ErrReceiptDoesNotExist(txHash)
|
||||
}
|
||||
|
||||
func (repository *InMemory) SetBlocksStatus(chainHead int64) {
|
||||
for key, block := range repository.blocks {
|
||||
if key < (chainHead - blocksFromHeadBeforeFinal) {
|
||||
@@ -79,18 +97,12 @@ func (repository *InMemory) MissingBlockNumbers(startingBlockNumber int64, endin
|
||||
return missingNumbers
|
||||
}
|
||||
|
||||
func NewInMemory() *InMemory {
|
||||
return &InMemory{
|
||||
HandleBlockCallCount: 0,
|
||||
blocks: make(map[int64]core.Block),
|
||||
contracts: make(map[string]core.Contract),
|
||||
logs: make(map[string][]core.Log),
|
||||
}
|
||||
}
|
||||
|
||||
func (repository *InMemory) CreateOrUpdateBlock(block core.Block) error {
|
||||
repository.HandleBlockCallCount++
|
||||
repository.blocks[block.Number] = block
|
||||
for _, transaction := range block.Transactions {
|
||||
repository.receipts[transaction.Hash] = transaction.Receipt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ import (
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
type BlockStatus int
|
||||
|
||||
type Postgres struct {
|
||||
Db *sqlx.DB
|
||||
node core.Node
|
||||
@@ -30,6 +28,10 @@ var (
|
||||
ErrUnableToSetNode = errors.New("postgres: unable to set node")
|
||||
)
|
||||
|
||||
var ErrReceiptDoesNotExist = func(txHash string) error {
|
||||
return errors.New(fmt.Sprintf("Receipt for tx: %v does not exist", txHash))
|
||||
}
|
||||
|
||||
var ErrContractDoesNotExist = func(contractHash string) error {
|
||||
return errors.New(fmt.Sprintf("Contract %v does not exist", contractHash))
|
||||
}
|
||||
@@ -290,13 +292,31 @@ func (repository Postgres) removeBlock(blockNumber int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repository Postgres) FindReceipt(txHash string) (core.Receipt, error) {
|
||||
row := repository.Db.QueryRow(
|
||||
`SELECT contract_address,
|
||||
tx_hash,
|
||||
cumulative_gas_used,
|
||||
gas_used,
|
||||
state_root,
|
||||
status
|
||||
FROM receipts
|
||||
WHERE tx_hash = $1`, txHash)
|
||||
receipt, err := loadReceipt(row)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
return core.Receipt{}, ErrReceiptDoesNotExist(txHash)
|
||||
default:
|
||||
return core.Receipt{}, err
|
||||
}
|
||||
}
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
func (repository Postgres) createTransactions(tx *sql.Tx, blockId int64, transactions []core.Transaction) error {
|
||||
for _, transaction := range transactions {
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO transactions
|
||||
(block_id, tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value, tx_input_data)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
blockId, transaction.Hash, transaction.Nonce, transaction.To, transaction.From, transaction.GasLimit, transaction.GasPrice, transaction.Value, transaction.Data)
|
||||
err := repository.createTransaction(tx, blockId, transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -304,6 +324,59 @@ func (repository Postgres) createTransactions(tx *sql.Tx, blockId int64, transac
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repository Postgres) createTransaction(tx *sql.Tx, blockId int64, transaction core.Transaction) error {
|
||||
var transactionId int
|
||||
err := tx.QueryRow(
|
||||
`INSERT INTO transactions
|
||||
(block_id, tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value, tx_input_data)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING id`,
|
||||
blockId, transaction.Hash, transaction.Nonce, transaction.To, transaction.From, transaction.GasLimit, transaction.GasPrice, transaction.Value, transaction.Data).
|
||||
Scan(&transactionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if transaction.Receipt.TxHash != "" {
|
||||
err = repository.createReceipt(tx, transactionId, transaction.Receipt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repository Postgres) createReceipt(tx *sql.Tx, transactionId int, receipt core.Receipt) error {
|
||||
//Not currently persisting log bloom filters
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO receipts
|
||||
(contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, transaction_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
||||
receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, transactionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadReceipt(receiptsRow *sql.Row) (core.Receipt, error) {
|
||||
var contractAddress string
|
||||
var txHash string
|
||||
var cumulativeGasUsed int64
|
||||
var gasUsed int64
|
||||
var stateRoot string
|
||||
var status int
|
||||
|
||||
err := receiptsRow.Scan(&contractAddress, &txHash, &cumulativeGasUsed, &gasUsed, &stateRoot, &status)
|
||||
return core.Receipt{
|
||||
TxHash: txHash,
|
||||
ContractAddress: contractAddress,
|
||||
CumulativeGasUsed: cumulativeGasUsed,
|
||||
GasUsed: gasUsed,
|
||||
StateRoot: stateRoot,
|
||||
Status: status,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (repository Postgres) loadBlock(blockRows *sql.Row) (core.Block, error) {
|
||||
var blockId int64
|
||||
var blockHash string
|
||||
|
||||
@@ -12,6 +12,7 @@ type Repository interface {
|
||||
FindBlockByNumber(blockNumber int64) (core.Block, error)
|
||||
MaxBlockNumber() int64
|
||||
MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64) []int64
|
||||
FindReceipt(txHash string) (core.Receipt, error)
|
||||
CreateContract(contract core.Contract) error
|
||||
ContractExists(contractHash string) bool
|
||||
FindContract(contractHash string) (core.Contract, error)
|
||||
|
||||
@@ -15,6 +15,7 @@ func ClearData(postgres repositories.Postgres) {
|
||||
postgres.Db.MustExec("DELETE FROM transactions")
|
||||
postgres.Db.MustExec("DELETE FROM blocks")
|
||||
postgres.Db.MustExec("DELETE FROM logs")
|
||||
postgres.Db.MustExec("DELETE FROM receipts")
|
||||
}
|
||||
|
||||
func AssertRepositoryBehavior(buildRepository func(node core.Node) repositories.Repository) {
|
||||
@@ -497,4 +498,43 @@ func AssertRepositoryBehavior(buildRepository func(node core.Node) repositories.
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Saving receipts", func() {
|
||||
It("returns the receipt when it exists", func() {
|
||||
expected := core.Receipt{
|
||||
ContractAddress: "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
|
||||
CumulativeGasUsed: 7996119,
|
||||
GasUsed: 21000,
|
||||
Logs: []core.Log{},
|
||||
StateRoot: "0x88abf7e73128227370aa7baa3dd4e18d0af70e92ef1f9ef426942fbe2dddb733",
|
||||
Status: 1,
|
||||
TxHash: "0xe340558980f89d5f86045ac11e5cc34e4bcec20f9f1e2a427aa39d87114e8223",
|
||||
}
|
||||
|
||||
transaction := core.Transaction{
|
||||
Hash: expected.TxHash,
|
||||
Receipt: expected,
|
||||
}
|
||||
|
||||
block := core.Block{Transactions: []core.Transaction{transaction}}
|
||||
repository.CreateOrUpdateBlock(block)
|
||||
receipt, err := repository.FindReceipt("0xe340558980f89d5f86045ac11e5cc34e4bcec20f9f1e2a427aa39d87114e8223")
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
//Not currently serializing bloom logs
|
||||
Expect(receipt.Bloom).To(Equal(core.Receipt{}.Bloom))
|
||||
Expect(receipt.TxHash).To(Equal(expected.TxHash))
|
||||
Expect(receipt.CumulativeGasUsed).To(Equal(expected.CumulativeGasUsed))
|
||||
Expect(receipt.GasUsed).To(Equal(expected.GasUsed))
|
||||
Expect(receipt.StateRoot).To(Equal(expected.StateRoot))
|
||||
Expect(receipt.Status).To(Equal(expected.Status))
|
||||
})
|
||||
|
||||
It("returns ErrReceiptDoesNotExist when receipt does not exist", func() {
|
||||
receipt, err := repository.FindReceipt("DOES NOT EXIST")
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(receipt).To(BeZero())
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user