parent
7501fe70a7
commit
71de8e970d
@ -7,6 +7,8 @@ import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/cmd"
|
||||
"github.com/8thlight/vulcanizedb/pkg/geth"
|
||||
"github.com/8thlight/vulcanizedb/pkg/watched_contracts"
|
||||
@ -15,14 +17,27 @@ import (
|
||||
func main() {
|
||||
environment := flag.String("environment", "", "Environment name")
|
||||
contractHash := flag.String("contract-hash", "", "Contract hash to show summary")
|
||||
_blockNumber := flag.Int64("block-number", -1, "Block number of summary")
|
||||
flag.Parse()
|
||||
config := cmd.LoadConfig(*environment)
|
||||
blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
|
||||
repository := cmd.LoadPostgres(config.Database)
|
||||
contractSummary, err := watched_contracts.NewSummary(blockchain, repository, *contractHash)
|
||||
blockNumber := requestedBlockNumber(_blockNumber)
|
||||
|
||||
contractSummary, err := watched_contracts.NewSummary(blockchain, repository, *contractHash, blockNumber)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
output := watched_contracts.GenerateConsoleOutput(contractSummary)
|
||||
fmt.Println(output)
|
||||
}
|
||||
|
||||
func requestedBlockNumber(blockNumber *int64) *big.Int {
|
||||
var _blockNumber *big.Int
|
||||
if *blockNumber == -1 {
|
||||
_blockNumber = nil
|
||||
} else {
|
||||
_blockNumber = big.NewInt(*blockNumber)
|
||||
}
|
||||
return _blockNumber
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ var _ = Describe("Reading from the Geth blockchain", func() {
|
||||
Expect(firstBlock.Number + 1).Should(Equal(secondBlock.Number))
|
||||
|
||||
close(done)
|
||||
}, 10)
|
||||
}, 15)
|
||||
|
||||
It("retrieves the genesis block and first block", func(done Done) {
|
||||
genesisBlock := blockchain.GetBlockByNumber(int64(0))
|
||||
@ -52,6 +52,6 @@ var _ = Describe("Reading from the Geth blockchain", func() {
|
||||
Expect(firstBlock.Number).To(Equal(int64(1)))
|
||||
|
||||
close(done)
|
||||
}, 10)
|
||||
}, 15)
|
||||
|
||||
})
|
||||
|
@ -1,10 +1,12 @@
|
||||
package core
|
||||
|
||||
import "math/big"
|
||||
|
||||
type Blockchain interface {
|
||||
GetBlockByNumber(blockNumber int64) Block
|
||||
SubscribeToBlocks(blocks chan Block)
|
||||
StartListening()
|
||||
StopListening()
|
||||
GetContract(contractHash string) (Contract, error)
|
||||
GetAttribute(contract Contract, attributeName string) (interface{}, error)
|
||||
GetAttribute(contract Contract, attributeName string, blockNumber *big.Int) (interface{}, error)
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package fakes
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
@ -22,8 +24,13 @@ func (blockchain *Blockchain) GetContract(contractHash string) (core.Contract, e
|
||||
return contract, err
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) GetAttribute(contract core.Contract, attributeName string) (interface{}, error) {
|
||||
result := blockchain.contractAttributes[contract.Hash][attributeName]
|
||||
func (blockchain *Blockchain) GetAttribute(contract core.Contract, attributeName string, blockNumber *big.Int) (interface{}, error) {
|
||||
var result interface{}
|
||||
if blockNumber == nil {
|
||||
result = blockchain.contractAttributes[contract.Hash+"-1"][attributeName]
|
||||
} else {
|
||||
result = blockchain.contractAttributes[contract.Hash+blockNumber.String()][attributeName]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@ -63,17 +70,23 @@ func (blockchain *Blockchain) StopListening() {
|
||||
blockchain.WasToldToStop = true
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) SetContractStateAttribute(contractHash string, attributeName string, attributeValue string) {
|
||||
contractStateAttributes := blockchain.contractAttributes[contractHash]
|
||||
if contractStateAttributes == nil {
|
||||
blockchain.contractAttributes[contractHash] = make(map[string]string)
|
||||
func (blockchain *Blockchain) SetContractStateAttribute(contractHash string, blockNumber *big.Int, attributeName string, attributeValue string) {
|
||||
var key string
|
||||
if blockNumber == nil {
|
||||
key = contractHash + "-1"
|
||||
} else {
|
||||
key = contractHash + blockNumber.String()
|
||||
}
|
||||
blockchain.contractAttributes[contractHash][attributeName] = attributeValue
|
||||
contractStateAttributes := blockchain.contractAttributes[key]
|
||||
if contractStateAttributes == nil {
|
||||
blockchain.contractAttributes[key] = make(map[string]string)
|
||||
}
|
||||
blockchain.contractAttributes[key][attributeName] = attributeValue
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) getContractAttributes(contractHash string) (core.ContractAttributes, error) {
|
||||
var contractAttributes core.ContractAttributes
|
||||
attributes, ok := blockchain.contractAttributes[contractHash]
|
||||
attributes, ok := blockchain.contractAttributes[contractHash+"-1"]
|
||||
if ok {
|
||||
for key, _ := range attributes {
|
||||
contractAttributes = append(contractAttributes, core.ContractAttribute{Name: key, Type: "string"})
|
||||
|
@ -7,9 +7,13 @@ import (
|
||||
|
||||
"sort"
|
||||
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/config"
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
@ -30,18 +34,40 @@ func (blockchain *GethBlockchain) GetContract(contractHash string) (core.Contrac
|
||||
}
|
||||
}
|
||||
|
||||
func (blockchain *GethBlockchain) GetAttribute(contract core.Contract, attributeName string) (interface{}, error) {
|
||||
boundContract, err := bindContract(common.HexToAddress(contract.Hash), blockchain.client, blockchain.client)
|
||||
func (blockchain *GethBlockchain) getParseAbi(contract core.Contract) (abi.ABI, error) {
|
||||
abiFilePath := filepath.Join(config.ProjectRoot(), "contracts", "public", fmt.Sprintf("%s.json", contract.Hash))
|
||||
parsed, err := ParseAbiFile(abiFilePath)
|
||||
if err != nil {
|
||||
return abi.ABI{}, err
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func (blockchain *GethBlockchain) GetAttribute(contract core.Contract, attributeName string, blockNumber *big.Int) (interface{}, error) {
|
||||
parsed, err := blockchain.getParseAbi(contract)
|
||||
var result interface{}
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
input, err := parsed.Pack(attributeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result interface{}
|
||||
err = boundContract.Call(&bind.CallOpts{}, &result, attributeName)
|
||||
output, err := callContract(contract, input, err, blockchain, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = parsed.Unpack(&result, attributeName, output)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidStateAttribute
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func callContract(contract core.Contract, input []byte, err error, blockchain *GethBlockchain, blockNumber *big.Int) ([]byte, error) {
|
||||
to := common.HexToAddress(contract.Hash)
|
||||
msg := ethereum.CallMsg{To: &to, Data: input}
|
||||
return blockchain.client.CallContract(context.Background(), msg, blockNumber)
|
||||
}
|
||||
|
||||
func (blockchain *GethBlockchain) getContractAttributes(contractHash string) (core.ContractAttributes, error) {
|
||||
abiFilePath := filepath.Join(config.ProjectRoot(), "contracts", "public", fmt.Sprintf("%s.json", contractHash))
|
||||
@ -56,12 +82,3 @@ func (blockchain *GethBlockchain) getContractAttributes(contractHash string) (co
|
||||
sort.Sort(contractAttributes)
|
||||
return contractAttributes, nil
|
||||
}
|
||||
|
||||
func bindContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (bind.BoundContract, error) {
|
||||
abiFilePath := filepath.Join(config.ProjectRoot(), "contracts", "public", fmt.Sprintf("%s.json", address.Hex()))
|
||||
parsed, err := ParseAbiFile(abiFilePath)
|
||||
if err != nil {
|
||||
return bind.BoundContract{}, err
|
||||
}
|
||||
return *bind.NewBoundContract(address, parsed, caller, transactor), nil
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package geth_test
|
||||
|
||||
//import (
|
||||
// "math/big"
|
||||
//
|
||||
// cfg "github.com/8thlight/vulcanizedb/pkg/config"
|
||||
// "github.com/8thlight/vulcanizedb/pkg/geth"
|
||||
// "github.com/8thlight/vulcanizedb/pkg/geth/testing"
|
||||
@ -57,19 +59,43 @@ package geth_test
|
||||
// contractHash := "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
|
||||
//
|
||||
// contract, _ := blockchain.GetContract(contractHash)
|
||||
// name, err := blockchain.GetAttribute(contract, "name")
|
||||
// name, err := blockchain.GetAttribute(contract, "name", nil)
|
||||
//
|
||||
// Expect(err).To(BeNil())
|
||||
// Expect(name).To(Equal("OMGToken"))
|
||||
// })
|
||||
//
|
||||
// It("returns the correct attribute for a real contract", func() {
|
||||
// config, _ := cfg.NewConfig("public")
|
||||
// blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
|
||||
// contractHash := "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
|
||||
//
|
||||
// contract, _ := blockchain.GetContract(contractHash)
|
||||
// name, err := blockchain.GetAttribute(contract, "name", nil)
|
||||
//
|
||||
// Expect(err).To(BeNil())
|
||||
// Expect(name).To(Equal("OMGToken"))
|
||||
// })
|
||||
//
|
||||
// It("returns the correct attribute for a real contract at a specific block height", func() {
|
||||
// config, _ := cfg.NewConfig("public")
|
||||
// blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
|
||||
// contractHash := "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
|
||||
//
|
||||
// contract, _ := blockchain.GetContract(contractHash)
|
||||
// name, err := blockchain.GetAttribute(contract, "name", big.NewInt(4652791))
|
||||
//
|
||||
// Expect(name).To(Equal("OMGToken"))
|
||||
// Expect(err).To(BeNil())
|
||||
// })
|
||||
//
|
||||
// It("returns an error when there is no ABI for the given contract", func() {
|
||||
// config, _ := cfg.NewConfig("public")
|
||||
// blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
|
||||
// contractHash := "MISSINGHASH"
|
||||
//
|
||||
// contract, _ := blockchain.GetContract(contractHash)
|
||||
// name, err := blockchain.GetAttribute(contract, "name")
|
||||
// name, err := blockchain.GetAttribute(contract, "name", nil)
|
||||
//
|
||||
// Expect(err).To(Equal(geth.ErrMissingAbiFile))
|
||||
// Expect(name).To(BeNil())
|
||||
@ -81,7 +107,7 @@ package geth_test
|
||||
// contractHash := "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
|
||||
//
|
||||
// contract, _ := blockchain.GetContract(contractHash)
|
||||
// name, err := blockchain.GetAttribute(contract, "missing_attribute")
|
||||
// name, err := blockchain.GetAttribute(contract, "missing_attribute", nil)
|
||||
//
|
||||
// Expect(err).To(Equal(geth.ErrInvalidStateAttribute))
|
||||
// Expect(name).To(BeNil())
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/8thlight/vulcanizedb/pkg/repositories"
|
||||
)
|
||||
@ -15,27 +17,29 @@ type ContractSummary struct {
|
||||
LastTransaction *core.Transaction
|
||||
blockChain core.Blockchain
|
||||
Attributes core.ContractAttributes
|
||||
BlockNumber *big.Int
|
||||
}
|
||||
|
||||
var NewContractNotWatchedErr = func(contractHash string) error {
|
||||
return errors.New(fmt.Sprintf("Contract %v not being watched", contractHash))
|
||||
}
|
||||
|
||||
func NewSummary(blockchain core.Blockchain, repository repositories.Repository, contractHash string) (ContractSummary, error) {
|
||||
func NewSummary(blockchain core.Blockchain, repository repositories.Repository, contractHash string, blockNumber *big.Int) (ContractSummary, error) {
|
||||
watchedContract := repository.FindWatchedContract(contractHash)
|
||||
if watchedContract != nil {
|
||||
return newContractSummary(blockchain, *watchedContract), nil
|
||||
return newContractSummary(blockchain, *watchedContract, blockNumber), nil
|
||||
} else {
|
||||
return ContractSummary{}, NewContractNotWatchedErr(contractHash)
|
||||
}
|
||||
}
|
||||
|
||||
func (contractSummary ContractSummary) GetStateAttribute(attributeName string) interface{} {
|
||||
result, _ := contractSummary.blockChain.GetAttribute(contractSummary.Contract, attributeName)
|
||||
var result interface{}
|
||||
result, _ = contractSummary.blockChain.GetAttribute(contractSummary.Contract, attributeName, contractSummary.BlockNumber)
|
||||
return result
|
||||
}
|
||||
|
||||
func newContractSummary(blockchain core.Blockchain, watchedContract core.WatchedContract) ContractSummary {
|
||||
func newContractSummary(blockchain core.Blockchain, watchedContract core.WatchedContract, blockNumber *big.Int) ContractSummary {
|
||||
contract, _ := blockchain.GetContract(watchedContract.Hash)
|
||||
return ContractSummary{
|
||||
blockChain: blockchain,
|
||||
@ -44,6 +48,7 @@ func newContractSummary(blockchain core.Blockchain, watchedContract core.Watched
|
||||
NumberOfTransactions: len(watchedContract.Transactions),
|
||||
LastTransaction: lastTransaction(watchedContract),
|
||||
Attributes: contract.Attributes,
|
||||
BlockNumber: blockNumber,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package watched_contracts_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/8thlight/vulcanizedb/pkg/fakes"
|
||||
"github.com/8thlight/vulcanizedb/pkg/repositories"
|
||||
@ -9,14 +11,18 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ bool = Describe("The watched contract summary", func() {
|
||||
func NewCurrentContractSummary(blockchain core.Blockchain, repository repositories.Repository, contractHash string) (watched_contracts.ContractSummary, error) {
|
||||
return watched_contracts.NewSummary(blockchain, repository, contractHash, nil)
|
||||
}
|
||||
|
||||
var _ = Describe("The watched contract summary", func() {
|
||||
|
||||
Context("when the given contract is not being watched", func() {
|
||||
It("returns an error", func() {
|
||||
repository := repositories.NewInMemory()
|
||||
blockchain := fakes.NewBlockchain()
|
||||
|
||||
contractSummary, err := watched_contracts.NewSummary(blockchain, repository, "123")
|
||||
contractSummary, err := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary).To(Equal(watched_contracts.ContractSummary{}))
|
||||
Expect(err).NotTo(BeNil())
|
||||
@ -30,7 +36,7 @@ var _ bool = Describe("The watched contract summary", func() {
|
||||
repository.CreateWatchedContract(watchedContract)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
|
||||
contractSummary, err := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, err := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary).NotTo(Equal(watched_contracts.ContractSummary{}))
|
||||
Expect(err).To(BeNil())
|
||||
@ -42,7 +48,7 @@ var _ bool = Describe("The watched contract summary", func() {
|
||||
repository.CreateWatchedContract(watchedContract)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, _ := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary.ContractHash).To(Equal("0x123"))
|
||||
})
|
||||
@ -60,7 +66,7 @@ var _ bool = Describe("The watched contract summary", func() {
|
||||
repository.CreateBlock(block)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, _ := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary.NumberOfTransactions).To(Equal(2))
|
||||
})
|
||||
@ -78,7 +84,7 @@ var _ bool = Describe("The watched contract summary", func() {
|
||||
repository.CreateBlock(block)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, _ := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary.LastTransaction.Hash).To(Equal("TRANSACTION2"))
|
||||
})
|
||||
@ -88,23 +94,38 @@ var _ bool = Describe("The watched contract summary", func() {
|
||||
watchedContract := core.WatchedContract{Hash: "0x123"}
|
||||
repository.CreateWatchedContract(watchedContract)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
blockchain.SetContractStateAttribute("0x123", "foo", "bar")
|
||||
blockchain.SetContractStateAttribute("0x123", nil, "foo", "bar")
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, _ := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
attribute := contractSummary.GetStateAttribute("foo")
|
||||
|
||||
Expect(attribute).To(Equal("bar"))
|
||||
})
|
||||
|
||||
It("gets contract state attribute for the contract from the blockchain at specific block height", func() {
|
||||
repository := repositories.NewInMemory()
|
||||
watchedContract := core.WatchedContract{Hash: "0x123"}
|
||||
repository.CreateWatchedContract(watchedContract)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
blockNumber := big.NewInt(1000)
|
||||
blockchain.SetContractStateAttribute("0x123", nil, "foo", "bar")
|
||||
blockchain.SetContractStateAttribute("0x123", blockNumber, "foo", "baz")
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123", blockNumber)
|
||||
attribute := contractSummary.GetStateAttribute("foo")
|
||||
|
||||
Expect(attribute).To(Equal("baz"))
|
||||
})
|
||||
|
||||
It("gets attributes for the contract from the blockchain", func() {
|
||||
repository := repositories.NewInMemory()
|
||||
watchedContract := core.WatchedContract{Hash: "0x123"}
|
||||
repository.CreateWatchedContract(watchedContract)
|
||||
blockchain := fakes.NewBlockchain()
|
||||
blockchain.SetContractStateAttribute("0x123", "foo", "bar")
|
||||
blockchain.SetContractStateAttribute("0x123", "baz", "bar")
|
||||
blockchain.SetContractStateAttribute("0x123", nil, "foo", "bar")
|
||||
blockchain.SetContractStateAttribute("0x123", nil, "baz", "bar")
|
||||
|
||||
contractSummary, _ := watched_contracts.NewSummary(blockchain, repository, "0x123")
|
||||
contractSummary, _ := NewCurrentContractSummary(blockchain, repository, "0x123")
|
||||
|
||||
Expect(contractSummary.Attributes).To(Equal(
|
||||
core.ContractAttributes{
|
||||
|
Loading…
Reference in New Issue
Block a user