From 38f6847ff283c99a331745f2a46f1d31b3d898f1 Mon Sep 17 00:00:00 2001
From: Elizabeth Engelman <emengelman@gmail.com>
Date: Mon, 5 Aug 2019 13:13:53 -0500
Subject: [PATCH] Create a HeaderSyncReceiptRepository

---
 .../repositories/header_repository.go         |  21 ---
 .../repositories/header_repository_test.go    |   3 +-
 .../header_sync_receipt_repository.go         |  44 ++++++
 .../header_sync_receipt_repository_test.go    | 129 ++++++++++++++++++
 pkg/datastore/repository.go                   |   4 +
 5 files changed, 179 insertions(+), 22 deletions(-)
 create mode 100644 pkg/datastore/postgres/repositories/header_sync_receipt_repository.go
 create mode 100644 pkg/datastore/postgres/repositories/header_sync_receipt_repository_test.go

diff --git a/pkg/datastore/postgres/repositories/header_repository.go b/pkg/datastore/postgres/repositories/header_repository.go
index 4429fe8d4..dc0baa0f5 100644
--- a/pkg/datastore/postgres/repositories/header_repository.go
+++ b/pkg/datastore/postgres/repositories/header_repository.go
@@ -85,27 +85,6 @@ func (repository HeaderRepository) CreateTransactionInTx(tx *sqlx.Tx, headerID i
 	return txId, err
 }
 
-func (repository HeaderRepository) CreateReceiptInTx(tx *sqlx.Tx, headerID, transactionID int64, receipt core.Receipt) (int64, error) {
-	var receiptId int64
-	addressId, getAddressErr := AddressRepository{}.GetOrCreateAddressInTransaction(tx, receipt.ContractAddress)
-	if getAddressErr != nil {
-		log.Error("createReceipt: Error getting address id: ", getAddressErr)
-		return receiptId, getAddressErr
-	}
-	err := tx.QueryRowx(`INSERT INTO public.header_sync_receipts
-               (header_id, transaction_id, contract_address_id, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp)
-               VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
-			   ON CONFLICT (header_id, transaction_id) DO UPDATE
-			   SET (contract_address_id, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp) = ($3, $4::NUMERIC, $5::NUMERIC, $6, $7, $8, $9)
-               RETURNING id`,
-		headerID, transactionID, addressId, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, receipt.TxHash, receipt.Rlp).Scan(&receiptId)
-	if err != nil {
-		log.Error("header_repository: error inserting receipt: ", err)
-		return receiptId, err
-	}
-	return receiptId, err
-}
-
 func (repository HeaderRepository) GetHeader(blockNumber int64) (core.Header, error) {
 	var header core.Header
 	err := repository.database.Get(&header, `SELECT id, block_number, hash, raw, block_timestamp FROM headers WHERE block_number = $1 AND eth_node_fingerprint = $2`,
diff --git a/pkg/datastore/postgres/repositories/header_repository_test.go b/pkg/datastore/postgres/repositories/header_repository_test.go
index bf9ea80c7..dba6da09a 100644
--- a/pkg/datastore/postgres/repositories/header_repository_test.go
+++ b/pkg/datastore/postgres/repositories/header_repository_test.go
@@ -216,7 +216,8 @@ var _ = Describe("Block header repository", func() {
 				Rlp:               []byte{1, 2, 3},
 			}
 
-			_, receiptErr := repo.CreateReceiptInTx(tx, headerID, txId, receipt)
+			receiptRepo := repositories.HeaderSyncReceiptRepository{}
+			_, receiptErr := receiptRepo.CreateHeaderSyncReceiptInTx(headerID, txId, receipt, tx)
 			Expect(receiptErr).ToNot(HaveOccurred())
 			commitErr := tx.Commit()
 			Expect(commitErr).ToNot(HaveOccurred())
diff --git a/pkg/datastore/postgres/repositories/header_sync_receipt_repository.go b/pkg/datastore/postgres/repositories/header_sync_receipt_repository.go
new file mode 100644
index 000000000..d23bf10d1
--- /dev/null
+++ b/pkg/datastore/postgres/repositories/header_sync_receipt_repository.go
@@ -0,0 +1,44 @@
+// Copyright 2018 Vulcanize
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package repositories
+
+import (
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/jmoiron/sqlx"
+	"github.com/vulcanize/vulcanizedb/pkg/core"
+)
+
+type HeaderSyncReceiptRepository struct{}
+
+func (HeaderSyncReceiptRepository) CreateHeaderSyncReceiptInTx(headerID, transactionID int64, receipt core.Receipt, tx *sqlx.Tx) (int64, error) {
+	var receiptId int64
+	addressId, getAddressErr := AddressRepository{}.GetOrCreateAddressInTransaction(tx, receipt.ContractAddress)
+	if getAddressErr != nil {
+		log.Error("createReceipt: Error getting address id: ", getAddressErr)
+		return receiptId, getAddressErr
+	}
+	err := tx.QueryRowx(`INSERT INTO public.header_sync_receipts
+               (header_id, transaction_id, contract_address_id, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp)
+               VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
+			   ON CONFLICT (header_id, transaction_id) DO UPDATE
+			   SET (contract_address_id, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp) = ($3, $4::NUMERIC, $5::NUMERIC, $6, $7, $8, $9)
+               RETURNING id`,
+		headerID, transactionID, addressId, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, receipt.TxHash, receipt.Rlp).Scan(&receiptId)
+	if err != nil {
+		log.Error("header_repository: error inserting receipt: ", err)
+		return receiptId, err
+	}
+	return receiptId, err
+}
diff --git a/pkg/datastore/postgres/repositories/header_sync_receipt_repository_test.go b/pkg/datastore/postgres/repositories/header_sync_receipt_repository_test.go
new file mode 100644
index 000000000..4a06554df
--- /dev/null
+++ b/pkg/datastore/postgres/repositories/header_sync_receipt_repository_test.go
@@ -0,0 +1,129 @@
+// Copyright 2018 Vulcanize
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package repositories_test
+
+import (
+	"encoding/json"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"github.com/vulcanize/vulcanizedb/pkg/core"
+	"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
+	"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
+	"github.com/vulcanize/vulcanizedb/test_config"
+	"math/big"
+)
+
+var _ = Describe("Header Sync Receipt Repo", func() {
+	var (
+		rawHeader []byte
+		err       error
+		timestamp string
+		db        *postgres.DB
+		receiptRepo repositories.HeaderSyncReceiptRepository
+		headerRepo repositories.HeaderRepository
+		header    core.Header
+	)
+
+	BeforeEach(func() {
+		rawHeader, err = json.Marshal(types.Header{})
+		Expect(err).NotTo(HaveOccurred())
+		timestamp = big.NewInt(123456789).String()
+
+		db = test_config.NewTestDB(test_config.NewTestNode())
+		test_config.CleanTestDB(db)
+		receiptRepo = repositories.HeaderSyncReceiptRepository{}
+		headerRepo = repositories.NewHeaderRepository(db)
+		header = core.Header{
+			BlockNumber: 100,
+			Hash:        common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(),
+			Raw:         rawHeader,
+			Timestamp:   timestamp,
+		}
+	})
+	Describe("creating a receipt", func() {
+		It("adds a receipt in a tx", func() {
+			headerID, err := headerRepo.CreateOrUpdateHeader(header)
+			Expect(err).NotTo(HaveOccurred())
+			fromAddress := common.HexToAddress("0x1234")
+			toAddress := common.HexToAddress("0x5678")
+			txHash := common.HexToHash("0x9876")
+			txIndex := big.NewInt(123)
+			transaction := core.TransactionModel{
+				Data:     []byte{},
+				From:     fromAddress.Hex(),
+				GasLimit: 0,
+				GasPrice: 0,
+				Hash:     txHash.Hex(),
+				Nonce:    0,
+				Raw:      []byte{},
+				To:       toAddress.Hex(),
+				TxIndex:  txIndex.Int64(),
+				Value:    "0",
+			}
+			tx, err := db.Beginx()
+			Expect(err).ToNot(HaveOccurred())
+			txId, txErr := headerRepo.CreateTransactionInTx(tx, headerID, transaction)
+			Expect(txErr).ToNot(HaveOccurred())
+
+			contractAddr := common.HexToAddress("0x1234")
+			stateRoot := common.HexToHash("0x5678")
+			receipt := core.Receipt{
+				ContractAddress:   contractAddr.Hex(),
+				TxHash:            txHash.Hex(),
+				GasUsed:           10,
+				CumulativeGasUsed: 100,
+				StateRoot:         stateRoot.Hex(),
+				Rlp:               []byte{1, 2, 3},
+			}
+
+			_, receiptErr := receiptRepo.CreateHeaderSyncReceiptInTx(headerID, txId, receipt, tx)
+			Expect(receiptErr).ToNot(HaveOccurred())
+			commitErr := tx.Commit()
+			Expect(commitErr).ToNot(HaveOccurred())
+
+			type idModel struct {
+				TransactionId     int64  `db:"transaction_id"`
+				ContractAddressId int64  `db:"contract_address_id"`
+				CumulativeGasUsed uint64 `db:"cumulative_gas_used"`
+				GasUsed           uint64 `db:"gas_used"`
+				StateRoot         string `db:"state_root"`
+				Status            int
+				TxHash            string `db:"tx_hash"`
+				Rlp               []byte `db:"rlp"`
+			}
+
+			var addressId int64
+			getAddressErr := db.Get(&addressId, `SELECT id FROM addresses WHERE address = $1`, contractAddr.Hex())
+			Expect(getAddressErr).NotTo(HaveOccurred())
+
+			var dbReceipt idModel
+			getReceiptErr := db.Get(&dbReceipt,
+				`SELECT transaction_id, contract_address_id, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp
+				FROM public.header_sync_receipts WHERE header_id = $1`, headerID)
+			Expect(getReceiptErr).NotTo(HaveOccurred())
+
+			Expect(dbReceipt.TransactionId).To(Equal(txId))
+			Expect(dbReceipt.TxHash).To(Equal(txHash.Hex()))
+			Expect(dbReceipt.ContractAddressId).To(Equal(addressId))
+			Expect(dbReceipt.CumulativeGasUsed).To(Equal(uint64(100)))
+			Expect(dbReceipt.GasUsed).To(Equal(uint64(10)))
+			Expect(dbReceipt.StateRoot).To(Equal(stateRoot.Hex()))
+			Expect(dbReceipt.Status).To(Equal(0))
+			Expect(dbReceipt.Rlp).To(Equal([]byte{1, 2, 3}))
+		})
+	})
+})
diff --git a/pkg/datastore/repository.go b/pkg/datastore/repository.go
index 5e94f7d9d..fe8bad9cc 100644
--- a/pkg/datastore/repository.go
+++ b/pkg/datastore/repository.go
@@ -62,6 +62,10 @@ type FullSyncReceiptRepository interface {
 	GetFullSyncReceipt(txHash string) (core.Receipt, error)
 }
 
+type HeaderSyncReceiptRepository interface {
+	CreateFullSyncReceiptInTx(blockId int64, receipt core.Receipt, tx *sqlx.Tx) (int64, error)
+}
+
 type WatchedEventRepository interface {
 	GetWatchedEvents(name string) ([]*core.WatchedEvent, error)
 }