Add FlipKick log events transformer

This commit is contained in:
Elizabeth 2018-08-07 10:51:34 -05:00 committed by GitHub
parent 66decaaa78
commit c617cd9c9d
1066 changed files with 200929 additions and 95 deletions

View File

@ -13,13 +13,18 @@ before_install:
# ginkgo golint dep migrate
- make installtools
- bash ./scripts/install-postgres-10.sh
- npm install -g ganache-cli
before_script:
- sudo -u postgres createdb vulcanize_private
- make migrate NAME=vulcanize_private
- bash ./libraries/maker/start_test_chain.sh
script:
- make test
notifications:
email: false
after_script:
- bash ./libraries/maker/stop_test_chain.sh

34
Gopkg.lock generated
View File

@ -17,7 +17,10 @@
name = "github.com/ethereum/go-ethereum"
packages = [
".",
"accounts",
"accounts/abi",
"accounts/abi/bind",
"accounts/keystore",
"common",
"common/hexutil",
"common/math",
@ -33,6 +36,7 @@
"crypto/bn256/cloudflare",
"crypto/bn256/google",
"crypto/ecies",
"crypto/randentropy",
"crypto/secp256k1",
"crypto/sha3",
"ethclient",
@ -209,12 +213,24 @@
revision = "c893efa28eb45626cdaa76c9f653b62488858837"
version = "v1.2.0"
[[projects]]
name = "github.com/pborman/uuid"
packages = ["."]
revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53"
version = "v1.1"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
[[projects]]
name = "github.com/rjeczalik/notify"
packages = ["."]
revision = "52ae50d8490436622a8941bd70c3dbe0acdd4bbf"
version = "v0.9.0"
[[projects]]
name = "github.com/rs/cors"
packages = ["."]
@ -282,7 +298,11 @@
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ripemd160"]
packages = [
"pbkdf2",
"ripemd160",
"scrypt"
]
revision = "613d6eafa307c6881a737a3c35c0e312e8d3a8c5"
[[projects]]
@ -336,6 +356,16 @@
]
revision = "be25de41fadfae372d6470bda81ca6beb55ef551"
[[projects]]
branch = "master"
name = "golang.org/x/tools"
packages = [
"go/ast/astutil",
"imports",
"internal/fastwalk"
]
revision = "8cc4e8a6f4841aa92a8683fca47bc5d64b58875b"
[[projects]]
name = "gopkg.in/fatih/set.v0"
packages = ["."]
@ -363,6 +393,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "a69d27ddc33f08d7b39242508f04e5c339b52cc65e70596100d17a870b2183a6"
inputs-digest = "2122d1d04fbc67daf75d751e144926e73f0fd838d51711cccf9604eabb46b95b"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -77,6 +77,16 @@ This command is useful when you want a minimal baseline from which to track targ
2. In a separate terminal start VulcanizeDB:
- `./vulcanizedb lightSync --config <config.toml> --starting-block-number <block-number>`
## Backfill Auction event logs from light sync
Backfills auction event logs from the configured Ethereum node based on the populated block headers.
This command requires that a light sync (see command above) has previously been run.
_Since auction contracts have not yet been deployed, this command will need to be run a local blockchain at the moment. As such, a new environment file will need to be added. See `environments/local.toml.example`._
1. Start Ethereum node
1. In a separate terminal run the backfill command:
- `./vulcanizedb backfillAuctionLogs --config <config.toml>`
## Start full environment in docker by single command
### Geth Rinkeby

View File

@ -0,0 +1,76 @@
// 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 cmd
import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/spf13/cobra"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/libraries/shared"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
"log"
)
// backfillAuctionLogsCmd represents the backfillAuctionLogs command
var backfillAuctionLogsCmd = &cobra.Command{
Use: "backfillAuctionLogs",
Short: "Backfill auction event logs",
Long: `Backfills auction event logs based on previously populated block Header records.
vulcanize backfillAuctionLogs --config environments/local.toml
This command expects a light sync to have been run, and the presence of header records in the Vulcanize database.`,
Run: func(cmd *cobra.Command, args []string) {
backfillAuctionLogs()
},
}
func blockChain() *geth.BlockChain {
rawRpcClient, err := rpc.Dial(ipc)
if err != nil {
log.Fatal(err)
}
rpcClient := client.NewRpcClient(rawRpcClient, ipc)
ethClient := ethclient.NewClient(rawRpcClient)
vdbEthClient := client.NewEthClient(ethClient)
vdbNode := node.MakeNode(rpcClient)
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
return geth.NewBlockChain(vdbEthClient, vdbNode, transactionConverter)
}
func backfillAuctionLogs() {
blockChain := blockChain()
db, err := postgres.NewDB(databaseConfig, blockChain.Node())
if err != nil {
log.Fatal("Failed to initialize database.")
}
watcher := shared.Watcher{
DB: *db,
Blockchain: blockChain,
}
watcher.AddTransformers(every_block.TransformerInitializers())
watcher.Execute()
}
func init() {
rootCmd.AddCommand(backfillAuctionLogsCmd)
}

View File

@ -0,0 +1 @@
DROP SCHEMA maker;

View File

@ -0,0 +1,2 @@
CREATE SCHEMA maker;

View File

@ -0,0 +1 @@
DROP TABLE maker.flip_kick;

View File

@ -0,0 +1,16 @@
CREATE TABLE maker.flip_kick (
db_id SERIAL PRIMARY KEY,
header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE,
id NUMERIC NOT NULL UNIQUE,
mom VARCHAR,
vat VARCHAR,
ilk VARCHAR,
lot NUMERIC,
bid NUMERIC,
guy VARCHAR,
gal VARCHAR,
"end" TIMESTAMP WITH TIME ZONE,
era TIMESTAMP WITH TIME ZONE,
lad VARCHAR,
tab NUMERIC
);

View File

@ -15,6 +15,13 @@ SET check_function_bodies = false;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: maker; Type: SCHEMA; Schema: -; Owner: -
--
CREATE SCHEMA maker;
--
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
--
@ -33,6 +40,48 @@ SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: flip_kick; Type: TABLE; Schema: maker; Owner: -
--
CREATE TABLE maker.flip_kick (
db_id integer NOT NULL,
header_id integer NOT NULL,
id numeric NOT NULL,
mom character varying,
vat character varying,
ilk character varying,
lot numeric,
bid numeric,
guy character varying,
gal character varying,
"end" timestamp with time zone,
era timestamp with time zone,
lad character varying,
tab numeric
);
--
-- Name: flip_kick_db_id_seq; Type: SEQUENCE; Schema: maker; Owner: -
--
CREATE SEQUENCE maker.flip_kick_db_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: flip_kick_db_id_seq; Type: SEQUENCE OWNED BY; Schema: maker; Owner: -
--
ALTER SEQUENCE maker.flip_kick_db_id_seq OWNED BY maker.flip_kick.db_id;
--
-- Name: logs; Type: TABLE; Schema: public; Owner: -
--
@ -405,6 +454,13 @@ CREATE VIEW public.watched_event_logs AS
WHERE ((((log_filters.topic0)::text = (logs.topic0)::text) OR (log_filters.topic0 IS NULL)) AND (((log_filters.topic1)::text = (logs.topic1)::text) OR (log_filters.topic1 IS NULL)) AND (((log_filters.topic2)::text = (logs.topic2)::text) OR (log_filters.topic2 IS NULL)) AND (((log_filters.topic3)::text = (logs.topic3)::text) OR (log_filters.topic3 IS NULL)));
--
-- Name: flip_kick db_id; Type: DEFAULT; Schema: maker; Owner: -
--
ALTER TABLE ONLY maker.flip_kick ALTER COLUMN db_id SET DEFAULT nextval('maker.flip_kick_db_id_seq'::regclass);
--
-- Name: blocks id; Type: DEFAULT; Schema: public; Owner: -
--
@ -468,6 +524,22 @@ ALTER TABLE ONLY public.transactions ALTER COLUMN id SET DEFAULT nextval('public
ALTER TABLE ONLY public.watched_contracts ALTER COLUMN contract_id SET DEFAULT nextval('public.watched_contracts_contract_id_seq'::regclass);
--
-- Name: flip_kick flip_kick_id_key; Type: CONSTRAINT; Schema: maker; Owner: -
--
ALTER TABLE ONLY maker.flip_kick
ADD CONSTRAINT flip_kick_id_key UNIQUE (id);
--
-- Name: flip_kick flip_kick_pkey; Type: CONSTRAINT; Schema: maker; Owner: -
--
ALTER TABLE ONLY maker.flip_kick
ADD CONSTRAINT flip_kick_pkey PRIMARY KEY (db_id);
--
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -599,6 +671,14 @@ CREATE INDEX tx_from_index ON public.transactions USING btree (tx_from);
CREATE INDEX tx_to_index ON public.transactions USING btree (tx_to);
--
-- Name: flip_kick flip_kick_header_id_fkey; Type: FK CONSTRAINT; Schema: maker; Owner: -
--
ALTER TABLE ONLY maker.flip_kick
ADD CONSTRAINT flip_kick_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
--
-- Name: transactions blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
--

View File

@ -0,0 +1,7 @@
[database]
name = "vulcanize_public"
hostname = "localhost"
port = 5432
[client]
ipcPath = "http://127.0.0.1:7546"

View File

@ -0,0 +1,27 @@
// 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 erc20_test_helpers
type TokenSupplyDBRow struct {
ID int64
Supply int64
BlockID int64 `db:"block_id"`
TokenAddress string `db:"token_address"`
}
type TransferDBRow struct {
ID int64 `db:"id"`
VulcanizeLogID int64 `db:"vulcanize_log_id"`
}

View File

@ -20,11 +20,12 @@ import (
"github.com/vulcanize/vulcanizedb/examples/constants"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
"github.com/vulcanize/vulcanizedb/examples/test_helpers"
"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/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/test_helpers"
"github.com/vulcanize/vulcanizedb/examples/erc20_test_helpers"
"math/big"
"strconv"
)
@ -68,11 +69,11 @@ var _ = Describe("Everyblock transformers", func() {
Expect(err).ToNot(HaveOccurred())
Expect(tokenSupplyCount).To(Equal(1))
var tokenSupply test_helpers.TokenSupplyDBRow
var tokenSupply erc20_test_helpers.TokenSupplyDBRow
err = db.Get(&tokenSupply, `SELECT * from token_supply where block_id = $1`, blockId)
Expect(err).ToNot(HaveOccurred())
Expect(tokenSupply.BlockID).To(Equal(blockId))
Expect(tokenSupply.TokenAddress).To(Equal(constants.DaiContractAddress))
Expect(tokenSupply.Supply).To(Equal(int64(0)))
})
})
})

View File

@ -19,12 +19,13 @@ import (
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
"github.com/vulcanize/vulcanizedb/examples/test_helpers"
"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/rand"
"github.com/vulcanize/vulcanizedb/pkg/test_helpers"
"github.com/vulcanize/vulcanizedb/examples/erc20_test_helpers"
)
var _ = Describe("ERC20 Token Repository", func() {
@ -52,8 +53,8 @@ var _ = Describe("ERC20 Token Repository", func() {
err := repository.Create(supply)
Expect(err).NotTo(HaveOccurred())
dbResult := test_helpers.TokenSupplyDBRow{}
expectedTokenSupply := test_helpers.TokenSupplyDBRow{
dbResult := erc20_test_helpers.TokenSupplyDBRow{}
expectedTokenSupply := erc20_test_helpers.TokenSupplyDBRow{
Supply: int64(100),
BlockID: blockId,
TokenAddress: testAddress,
@ -112,7 +113,7 @@ var _ = Describe("ERC20 Token Repository", func() {
err := node2TokenSupplyRepo.Create(tokenSupply)
Expect(err).NotTo(HaveOccurred())
var tokenSupplies []test_helpers.TokenSupplyDBRow
var tokenSupplies []erc20_test_helpers.TokenSupplyDBRow
err = node2TokenSupplyRepo.DB.Select(&tokenSupplies, `SELECT * FROM token_supply`)
Expect(err).NotTo(HaveOccurred())
Expect(len(tokenSupplies)).To(Equal(1))

View File

@ -20,7 +20,7 @@ import (
"github.com/vulcanize/vulcanizedb/examples/constants"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
"github.com/vulcanize/vulcanizedb/examples/mocks"
"github.com/vulcanize/vulcanizedb/examples/erc20_test_helpers/mocks"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"math/big"
"math/rand"

View File

@ -0,0 +1,31 @@
// 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 every_block
type TransformerConfig struct {
ContractAddress string
ContractAbi string
Topics []string
StartingBlockNumber int64
EndingBlockNumber int64
}
var FlipKickConfig = TransformerConfig{
ContractAddress: "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d", //this is a temporary address deployed locally
ContractAbi: FlipperABI,
Topics: []string{FlipKickSignature},
StartingBlockNumber: 0,
EndingBlockNumber: 100,
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,105 @@
// 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 every_block
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"strings"
"time"
"math/big"
"errors"
)
type Converter interface {
ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (*FlipKickEntity, error)
ToModel(flipKick FlipKickEntity) (FlipKickModel, error)
}
type FlipKickConverter struct{}
func (FlipKickConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (*FlipKickEntity, error) {
entity := &FlipKickEntity{}
address := common.HexToAddress(contractAddress)
abi, err := geth.ParseAbi(contractAbi)
if err != nil {
return entity, err
}
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
err = contract.UnpackLog(entity, "FlipKick", ethLog)
if err != nil {
return entity, err
}
return entity, nil
}
func (FlipKickConverter) ToModel(flipKick FlipKickEntity) (FlipKickModel, error) {
//TODO: Confirm if the following values can be/ever will be nil
if flipKick.Id == nil {
return FlipKickModel{}, errors.New("FlipKick log ID cannot be nil.")
}
id := flipKick.Id.String()
mom := strings.ToLower(flipKick.Mom.String())
vat := strings.ToLower(flipKick.Vat.String())
ilk := strings.ToLower(common.ToHex(flipKick.Ilk[:]))
lot := convertNilToEmptyString(flipKick.Lot.String())
bid := convertNilToEmptyString(flipKick.Bid.String())
guy := strings.ToLower(flipKick.Guy.String())
gal := strings.ToLower(flipKick.Gal.String())
endValue := convertNilToZeroTimeValue(flipKick.End)
end := time.Unix(endValue, 0)
eraValue := convertNilToZeroTimeValue(flipKick.Era)
era := time.Unix(eraValue, 0)
lad := strings.ToLower(flipKick.Lad.String())
tab := convertNilToEmptyString(flipKick.Tab.String())
return FlipKickModel{
Id: id,
Mom: mom,
Vat: vat,
Ilk: ilk,
Lot: lot,
Bid: bid,
Guy: guy,
Gal: gal,
End: end,
Era: era,
Lad: lad,
Tab: tab,
}, nil
}
func convertNilToZeroTimeValue(value *big.Int) int64 {
if value == nil {
return int64(0)
} else {
return value.Int64()
}
}
func convertNilToEmptyString(value string) string {
if value == "<nil>" {
return ""
} else {
return value
}
}

View File

@ -0,0 +1,109 @@
// 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 every_block_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/libraries/maker/test_data"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"math/big"
)
var _ = Describe("FlipKickEntity Converter", func() {
It("converts an Eth Log to and Entity", func() {
converter := every_block.FlipKickConverter{}
entity, err := converter.ToEntity(test_data.TemporaryFlipAddress, every_block.FlipperABI, test_data.EthFlipKickLog)
Expect(err).NotTo(HaveOccurred())
Expect(entity.Id).To(Equal(test_data.FlipKickEntity.Id))
Expect(entity.Mom).To(Equal(test_data.FlipKickEntity.Mom))
Expect(entity.Vat).To(Equal(test_data.FlipKickEntity.Vat))
Expect(entity.Ilk).To(Equal(test_data.FlipKickEntity.Ilk))
Expect(entity.Lot).To(Equal(test_data.FlipKickEntity.Lot))
Expect(entity.Bid).To(Equal(test_data.FlipKickEntity.Bid))
Expect(entity.Guy).To(Equal(test_data.FlipKickEntity.Guy))
Expect(entity.Gal).To(Equal(test_data.FlipKickEntity.Gal))
Expect(entity.End).To(Equal(test_data.FlipKickEntity.End))
Expect(entity.Era).To(Equal(test_data.FlipKickEntity.Era))
Expect(entity.Lad).To(Equal(test_data.FlipKickEntity.Lad))
Expect(entity.Tab).To(Equal(test_data.FlipKickEntity.Tab))
})
It("returns an error if converting log to entity fails", func() {
converter := every_block.FlipKickConverter{}
_, err := converter.ToEntity(test_data.TemporaryFlipAddress, "error abi", test_data.EthFlipKickLog)
Expect(err).To(HaveOccurred())
})
It("converts and Entity to a Model", func() {
converter := every_block.FlipKickConverter{}
model, err := converter.ToModel(test_data.FlipKickEntity)
Expect(err).NotTo(HaveOccurred())
Expect(model).To(Equal(test_data.FlipKickModel))
})
It("handles nil", func() {
emptyAddressHex := "0x0000000000000000000000000000000000000000"
emptyByteArrayHex := "0x0000000000000000000000000000000000000000000000000000000000000000"
emptyString := ""
emptyTime := time.Unix(0, 0)
converter := every_block.FlipKickConverter{}
emptyEntity := every_block.FlipKickEntity{
Id: big.NewInt(1),
Mom: common.Address{},
Vat: common.Address{},
Ilk: [32]byte{},
Lot: nil,
Bid: nil,
Guy: common.Address{},
Gal: common.Address{},
End: nil,
Era: nil,
Lad: common.Address{},
Tab: nil,
Raw: types.Log{},
}
model, err := converter.ToModel(emptyEntity)
Expect(err).NotTo(HaveOccurred())
Expect(model.Id).To(Equal("1"))
Expect(model.Mom).To(Equal(emptyAddressHex))
Expect(model.Vat).To(Equal(emptyAddressHex))
Expect(model.Ilk).To(Equal(emptyByteArrayHex))
Expect(model.Lot).To(Equal(emptyString))
Expect(model.Bid).To(Equal(emptyString))
Expect(model.Guy).To(Equal(emptyAddressHex))
Expect(model.Gal).To(Equal(emptyAddressHex))
Expect(model.End).To(Equal(emptyTime))
Expect(model.Era).To(Equal(emptyTime))
Expect(model.Lad).To(Equal(emptyAddressHex))
Expect(model.Tab).To(Equal(emptyString))
})
It("returns an error of the flip kick event id is nil", func() {
converter := every_block.FlipKickConverter{}
emptyEntity := every_block.FlipKickEntity{}
_, err := converter.ToModel(emptyEntity)
Expect(err).To(HaveOccurred())
})
})

View File

@ -0,0 +1,37 @@
// 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 every_block
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"math/big"
)
type FlipKickEntity struct {
Id *big.Int
Mom common.Address
Vat common.Address
Ilk [32]byte
Lot *big.Int
Bid *big.Int
Guy common.Address
Gal common.Address
End *big.Int
Era *big.Int
Lad common.Address
Tab *big.Int
Raw types.Log
}

View File

@ -0,0 +1,19 @@
package every_block_test
import (
"io/ioutil"
"log"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestEveryBlock(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "EveryBlock Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})

View File

@ -0,0 +1,52 @@
// 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 every_block
import (
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/core"
)
type LogFetcher interface {
FetchLogs(contractAddress string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error)
}
type Fetcher struct {
Blockchain core.BlockChain
}
func NewFetcher(blockchain core.BlockChain) Fetcher {
return Fetcher{
Blockchain: blockchain,
}
}
func (f Fetcher) FetchLogs(contractAddress string, topicZeros [][]common.Hash, blockNumber int64) ([]types.Log, error) {
block := big.NewInt(blockNumber)
address := common.HexToAddress(contractAddress)
query := ethereum.FilterQuery{
FromBlock: block,
ToBlock: block,
Addresses: []common.Address{address},
Topics: topicZeros,
}
return f.Blockchain.GetEthLogsWithCustomQuery(query)
}

View File

@ -0,0 +1,62 @@
// 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 every_block_test
import (
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
)
var _ = Describe("Fetcher", func() {
Describe("FetchLogs", func() {
var blockChain *fakes.MockBlockChain
var fetcher every_block.Fetcher
BeforeEach(func() {
blockChain = fakes.NewMockBlockChain()
fetcher = every_block.Fetcher{Blockchain: blockChain}
})
It("fetches logs based on the given query", func() {
blockNumber := int64(3)
address := "0x4D2"
topicZeros := [][]common.Hash{{common.HexToHash("0x")}}
query := ethereum.FilterQuery{
FromBlock: big.NewInt(blockNumber),
ToBlock: big.NewInt(blockNumber),
Addresses: []common.Address{common.HexToAddress(address)},
Topics: topicZeros,
}
fetcher.FetchLogs(address, topicZeros, blockNumber)
blockChain.AssertGetEthLogsWithCustomQueryCalledWith(query)
})
It("returns an error if fetching the logs fails", func() {
blockChain.SetGetLogsErr(fakes.FakeError)
_, err := fetcher.FetchLogs("", [][]common.Hash{}, int64(1))
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
})
})

View File

@ -0,0 +1,90 @@
// 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 every_block_test
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/libraries/maker/test_data"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
)
var _ = Describe("Integration tests", func() {
It("Fetches FlipKickEntity event logs from a local test chain", func() {
ipcPath := "http://127.0.0.1:7545"
rawRpcClient, err := rpc.Dial(ipcPath)
Expect(err).NotTo(HaveOccurred())
rpcClient := client.NewRpcClient(rawRpcClient, ipcPath)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
realNode := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
realBlockChain := geth.NewBlockChain(blockChainClient, realNode, transactionConverter)
realFetcher := every_block.NewFetcher(realBlockChain)
topic0 := common.HexToHash(every_block.FlipKickSignature)
topics := [][]common.Hash{{topic0}}
result, err := realFetcher.FetchLogs(test_data.TemporaryFlipAddress, topics, int64(10))
Expect(err).NotTo(HaveOccurred())
Expect(len(result) > 0).To(BeTrue())
Expect(result[0].Address).To(Equal(test_data.EthFlipKickLog.Address))
Expect(result[0].TxHash).To(Equal(test_data.EthFlipKickLog.TxHash))
Expect(result[0].BlockNumber).To(Equal(test_data.EthFlipKickLog.BlockNumber))
Expect(result[0].Topics).To(Equal(test_data.EthFlipKickLog.Topics))
Expect(result[0].Index).To(Equal(test_data.EthFlipKickLog.Index))
Expect(result[0].Data).To(Equal(test_data.EthFlipKickLog.Data))
})
It("unpacks an event log", func() {
address := common.HexToAddress(test_data.TemporaryFlipAddress)
abi, err := geth.ParseAbi(every_block.FlipperABI)
Expect(err).NotTo(HaveOccurred())
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
entity := &every_block.FlipKickEntity{}
var eventLog = test_data.EthFlipKickLog
err = contract.UnpackLog(entity, "FlipKick", eventLog)
Expect(err).NotTo(HaveOccurred())
expectedEntity := test_data.FlipKickEntity
Expect(entity.Id).To(Equal(expectedEntity.Id))
Expect(entity.Mom).To(Equal(expectedEntity.Mom))
Expect(entity.Vat).To(Equal(expectedEntity.Vat))
Expect(entity.Ilk).To(Equal(expectedEntity.Ilk))
Expect(entity.Lot).To(Equal(expectedEntity.Lot))
Expect(entity.Bid.String()).To(Equal(expectedEntity.Bid.String())) //FIXME
Expect(entity.Guy).To(Equal(expectedEntity.Guy))
Expect(entity.Gal).To(Equal(expectedEntity.Gal))
Expect(entity.End).To(Equal(expectedEntity.End))
Expect(entity.Era).To(Equal(expectedEntity.Era))
Expect(entity.Lad).To(Equal(expectedEntity.Lad))
Expect(entity.Tab).To(Equal(expectedEntity.Tab))
})
})

View File

@ -0,0 +1,32 @@
// 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 every_block
import "time"
type FlipKickModel struct {
Id string
Mom string
Vat string
Ilk string
Lot string
Bid string
Guy string
Gal string
End time.Time
Era time.Time
Lad string
Tab string
}

View File

@ -0,0 +1,71 @@
// 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 every_block
import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
)
type Repository interface {
Create(headerId int64, flipKick FlipKickModel) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type FlipKickRepository struct {
DB *postgres.DB
}
func NewFlipKickRepository(db *postgres.DB) FlipKickRepository {
return FlipKickRepository{DB: db}
}
func (fkr FlipKickRepository) Create(headerId int64, flipKick FlipKickModel) error {
_, err := fkr.DB.Exec(
`INSERT into maker.flip_kick (header_id, id, mom, vat, ilk, lot, bid, guy, gal, "end", era, lad, tab)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,
headerId, flipKick.Id, flipKick.Mom, flipKick.Vat, flipKick.Ilk, flipKick.Lot, flipKick.Bid, flipKick.Guy, flipKick.Gal, flipKick.End, flipKick.Era, flipKick.Lad, flipKick.Tab,
)
if err != nil {
return err
}
return nil
}
func (fkr FlipKickRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
var result []core.Header
err := fkr.DB.Select(
&result,
`SELECT headers.id, headers.block_number FROM headers
LEFT JOIN maker.flip_kick on headers.id = header_id
WHERE header_id ISNULL
AND headers.block_number >= $1
AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`,
startingBlockNumber,
endingBlockNumber,
fkr.DB.Node.ID,
)
if err != nil {
fmt.Println("Error:", err)
return result, err
}
return result, nil
}

View File

@ -0,0 +1,176 @@
// 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 every_block_test
import (
"math/rand"
"github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/libraries/maker/test_data"
"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/pkg/test_helpers"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("FlipKick Repository", func() {
var db *postgres.DB
var flipKickRepository every_block.FlipKickRepository
var headerId int64
var blockNumber int64
var flipKick = test_data.FlipKickModel
BeforeEach(func() {
db = test_helpers.CreateNewDatabase()
flipKickRepository = every_block.FlipKickRepository{DB: db}
blockNumber = rand.Int63()
headerId = createHeader(db, blockNumber)
_, err := db.Exec(`DELETE from maker.flip_kick;`)
Expect(err).NotTo(HaveOccurred())
})
Describe("Create", func() {
AfterEach(func() {
_, err := db.Exec(`DELETE from headers;`)
Expect(err).NotTo(HaveOccurred())
})
It("persists a flip_kick record", func() {
err := flipKickRepository.Create(headerId, flipKick)
Expect(err).NotTo(HaveOccurred())
assertDBRecordCount(db, "maker.flip_kick", 1)
dbResult := test_data.FlipKickDBRow{}
err = flipKickRepository.DB.QueryRowx(`SELECT * FROM maker.flip_kick`).StructScan(&dbResult)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.HeaderId).To(Equal(headerId))
Expect(dbResult.Id).To(Equal(flipKick.Id))
Expect(dbResult.Mom).To(Equal(flipKick.Mom))
Expect(dbResult.Vat).To(Equal(flipKick.Vat))
Expect(dbResult.Ilk).To(Equal(flipKick.Ilk))
Expect(dbResult.Lot).To(Equal(flipKick.Lot))
Expect(dbResult.Bid).To(Equal(flipKick.Bid))
Expect(dbResult.Guy).To(Equal(flipKick.Guy))
Expect(dbResult.Gal).To(Equal(flipKick.Gal))
Expect(dbResult.End.Equal(flipKick.End)).To(BeTrue())
Expect(dbResult.Era.Equal(flipKick.Era)).To(BeTrue())
Expect(dbResult.Lad).To(Equal(flipKick.Lad))
Expect(dbResult.Tab).To(Equal(flipKick.Tab))
})
It("returns an error if inserting the flip_kick record fails", func() {
err := flipKickRepository.Create(headerId, test_data.FlipKickModel)
Expect(err).NotTo(HaveOccurred())
err = flipKickRepository.Create(headerId, test_data.FlipKickModel)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
})
It("deletes the flip_kick records if its corresponding header record is deleted", func() {
err := flipKickRepository.Create(headerId, test_data.FlipKickModel)
Expect(err).NotTo(HaveOccurred())
assertDBRecordCount(db, "maker.flip_kick", 1)
assertDBRecordCount(db, "headers", 1)
_, err = db.Exec(`DELETE FROM headers where id = $1`, headerId)
Expect(err).NotTo(HaveOccurred())
assertDBRecordCount(db, "headers", 0)
assertDBRecordCount(db, "maker.flip_kick", 0)
})
})
Describe("When there are multiple nodes", func() {
var db2 *postgres.DB
var flipKickRepository2 every_block.FlipKickRepository
var headerId2 int64
BeforeEach(func() {
//create database for the second node
node2 := core.Node{
GenesisBlock: "GENESIS",
NetworkID: 1,
ID: "node2",
ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9",
}
db2 = test_config.NewTestDBWithoutDeletingRecords(node2)
flipKickRepository2 = every_block.FlipKickRepository{DB: db2}
headerId2 = createHeader(db2, blockNumber)
_, err := db2.Exec(`DELETE from maker.flip_kick;`)
Expect(err).NotTo(HaveOccurred())
})
It("only includes missing headers for the current node", func() {
node1missingHeaders, err := flipKickRepository.MissingHeaders(blockNumber, blockNumber)
Expect(err).NotTo(HaveOccurred())
Expect(len(node1missingHeaders)).To(Equal(1))
node2MissingHeaders, err := flipKickRepository2.MissingHeaders(blockNumber, blockNumber)
Expect(err).NotTo(HaveOccurred())
Expect(len(node2MissingHeaders)).To(Equal(1))
})
})
Describe("MissingHeaders", func() {
It("returns headers for which there isn't an associated flip_kick record", func() {
startingBlock := blockNumber - 3
endingBlock := blockNumber + 3
err := flipKickRepository.Create(headerId, test_data.FlipKickModel)
Expect(err).NotTo(HaveOccurred())
newBlockNumber := blockNumber + 3
newHeaderId := createHeader(db, newBlockNumber)
createHeader(db, blockNumber+10) //this one is out of the block range and shouldn't be included
headers, err := flipKickRepository.MissingHeaders(startingBlock, endingBlock)
Expect(len(headers)).To(Equal(1))
Expect(headers[0].Id).To(Equal(newHeaderId))
Expect(headers[0].BlockNumber).To(Equal(newBlockNumber))
})
})
})
func assertDBRecordCount(db *postgres.DB, dbTable string, expectedCount int) {
var count int
query := `SELECT count(*) FROM ` + dbTable
err := db.QueryRow(query).Scan(&count)
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(expectedCount))
}
func createHeader(db *postgres.DB, blockNumber int64) (headerId int64) {
headerRepository := repositories.NewHeaderRepository(db)
header := core.Header{
BlockNumber: blockNumber,
Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(),
Raw: []byte{1, 2, 3, 4, 5},
}
_, err := headerRepository.CreateOrUpdateHeader(header)
Expect(err).NotTo(HaveOccurred())
var dbHeader core.Header
err = db.Get(&dbHeader, `SELECT id, block_number, hash, raw FROM public.headers WHERE block_number = $1 AND eth_node_id = $2`, header.BlockNumber, db.NodeID)
Expect(err).NotTo(HaveOccurred())
return dbHeader.Id
}

View File

@ -0,0 +1,126 @@
// 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 every_block
import (
"errors"
"fmt"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/libraries/shared"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
)
type FlipKickTransformer struct {
Fetcher LogFetcher
Converter Converter
Repository Repository
Config TransformerConfig
}
type FlipKickTransformerInitializer struct {
Config TransformerConfig
}
func (i FlipKickTransformerInitializer) NewFlipKickTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
fetcher := NewFetcher(blockChain)
repository := NewFlipKickRepository(db)
transformer := FlipKickTransformer{
Fetcher: fetcher,
Repository: repository,
Converter: FlipKickConverter{},
Config: i.Config,
}
return transformer
}
func (fkt *FlipKickTransformer) SetConfig(config TransformerConfig) {
fkt.Config = config
}
const (
FetcherError = "Error fetching FlipKick log events for block number %d: %s"
LogToEntityError = "Error converting eth log to FlipKick entity for block number %d: %s"
EntityToModelError = "Error converting eth log to FlipKick entity for block number %d: %s"
RepositoryError = "Error creating flip_kick record for block number %d: %s"
TransformerError = "There has been %d error(s) transforming FlipKick event logs, see the logs for more details."
)
type transformerError struct {
err string
blockNumber int64
msg string
}
func (te *transformerError) Error() string {
return fmt.Sprintf(te.msg, te.blockNumber, te.err)
}
func newTransformerError(err error, blockNumber int64, msg string) error {
e := transformerError{err.Error(), blockNumber, msg}
log.Println(e.Error())
return &e
}
func (fkt FlipKickTransformer) Execute() error {
config := fkt.Config
topics := [][]common.Hash{{common.HexToHash(FlipKickSignature)}}
headers, err := fkt.Repository.MissingHeaders(config.StartingBlockNumber, config.EndingBlockNumber)
if err != nil {
log.Println("Error:", err)
return err
}
log.Printf("Fetching event logs for %d headers \n", len(headers))
var resultingErrors []error
for _, header := range headers {
ethLogs, err := fkt.Fetcher.FetchLogs(config.ContractAddress, topics, header.BlockNumber)
if err != nil {
resultingErrors = append(resultingErrors, newTransformerError(err, header.BlockNumber, FetcherError))
}
for _, ethLog := range ethLogs {
entity, err := fkt.Converter.ToEntity(config.ContractAddress, config.ContractAbi, ethLog)
if err != nil {
resultingErrors = append(resultingErrors, newTransformerError(err, header.BlockNumber, LogToEntityError))
}
model, err := fkt.Converter.ToModel(*entity)
if err != nil {
resultingErrors = append(resultingErrors, newTransformerError(err, header.BlockNumber, EntityToModelError))
}
err = fkt.Repository.Create(header.Id, model)
if err != nil {
resultingErrors = append(resultingErrors, newTransformerError(err, header.BlockNumber, RepositoryError))
}
}
}
if len(resultingErrors) > 0 {
for _, err := range resultingErrors {
log.Println(err)
}
msg := fmt.Sprintf(TransformerError, len(resultingErrors))
return errors.New(msg)
}
return nil
}

View File

@ -0,0 +1,142 @@
// 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 every_block_test
import (
"math/rand"
"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/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/libraries/maker/test_data"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
)
var _ = Describe("FlipKick Transformer", func() {
var transformer every_block.FlipKickTransformer
var fetcher test_data.MockLogFetcher
var converter test_data.MockFlipKickConverter
var repository test_data.MockFlipKickRepository
var testConfig every_block.TransformerConfig
var blockNumber int64
var headerId int64
var headers []core.Header
var logs []types.Log
BeforeEach(func() {
fetcher = test_data.MockLogFetcher{}
converter = test_data.MockFlipKickConverter{}
repository = test_data.MockFlipKickRepository{}
transformer = every_block.FlipKickTransformer{
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
startingBlockNumber := rand.Int63()
testConfig = every_block.TransformerConfig{
ContractAddress: "0x12345",
ContractAbi: "test abi",
Topics: []string{every_block.FlipKickSignature},
StartingBlockNumber: startingBlockNumber,
EndingBlockNumber: startingBlockNumber + 5,
}
transformer.SetConfig(testConfig)
blockNumber = rand.Int63()
headerId = rand.Int63()
headers = []core.Header{{
Id: headerId,
BlockNumber: blockNumber,
Hash: "0x",
Raw: nil,
}}
repository.SetHeadersToReturn(headers)
logs = []types.Log{test_data.EthFlipKickLog}
fetcher.SetFetchedLogs(logs)
})
It("fetches logs with the configured contract and topic(s) for each block", func() {
expectedTopics := [][]common.Hash{{common.HexToHash(every_block.FlipKickSignature)}}
err := transformer.Execute()
Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedContractAddress).To(Equal(testConfig.ContractAddress))
Expect(fetcher.FetchedTopics).To(Equal(expectedTopics))
Expect(fetcher.FetchedBlocks).To(Equal([]int64{blockNumber}))
})
It("returns an error if the fetcher fails", func() {
fetcher.SetFetcherError(fakes.FakeError)
err := transformer.Execute()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("error(s) transforming FlipKick event logs"))
})
It("converts the logs", func() {
err := transformer.Execute()
Expect(err).NotTo(HaveOccurred())
Expect(converter.ConverterContract).To(Equal(testConfig.ContractAddress))
Expect(converter.ConverterAbi).To(Equal(testConfig.ContractAbi))
Expect(converter.LogsToConvert).To(Equal(logs))
Expect(converter.EntitiesToConvert).To(Equal([]every_block.FlipKickEntity{test_data.FlipKickEntity}))
})
It("returns an error if converting the geth log fails", func() {
converter.SetConverterError(fakes.FakeError)
err := transformer.Execute()
Expect(err).To(HaveOccurred())
})
It("persists a flip_kick record", func() {
err := transformer.Execute()
Expect(err).NotTo(HaveOccurred())
Expect(repository.HeaderIds).To(Equal([]int64{headerId}))
Expect(repository.FlipKicksCreated).To(Equal([]every_block.FlipKickModel{test_data.FlipKickModel}))
})
It("returns an error if persisting a record fails", func() {
repository.SetCreateRecordError(fakes.FakeError)
err := transformer.Execute()
Expect(err).To(HaveOccurred())
})
It("returns an error if fetching missing headers fails", func() {
repository.SetMissingHeadersError(fakes.FakeError)
err := transformer.Execute()
Expect(err).To(HaveOccurred())
})
It("gets missing headers for blocks between the configured block number range", func() {
err := transformer.Execute()
Expect(err).NotTo(HaveOccurred())
Expect(repository.StartingBlockNumber).To(Equal(testConfig.StartingBlockNumber))
Expect(repository.EndingBlockNumber).To(Equal(testConfig.EndingBlockNumber))
})
})

View File

@ -0,0 +1,27 @@
// 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 every_block
import (
"github.com/vulcanize/vulcanizedb/libraries/shared"
)
func TransformerInitializers() []shared.TransformerInitializer {
config := FlipKickConfig
initializer := FlipKickTransformerInitializer{Config: config}
return []shared.TransformerInitializer{
initializer.NewFlipKickTransformer,
}
}

View File

@ -0,0 +1,10 @@
#!/bin/bash
MNEMONIC_PHRASE="whisper ordinary mystery awesome wood fox auction february blind volcano spare soft"
PORT=7545
DATABASE_PATH=libraries/maker/test_data/test_chain/
echo Starting ganache chain on port $PORT...
ganache-cli --port $PORT \
--db $DATABASE_PATH \
2>&1 > ganache-output.log &

View File

@ -0,0 +1,4 @@
#!/bin/bash
echo "Stopping ganache chain on port 7545"
ps -ef | grep ganache | grep -v grep | awk '{print $2}' | xargs kill

View File

@ -0,0 +1,98 @@
// 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 test_data
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"math/big"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"time"
)
var TemporaryFlipAddress = "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d"
var TemporaryFlipKickTransaction = "0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191"
var Topic0Hex = "0xc2d733c352a325d6ecf23d1cf0a189dbcc236b0636388b8c5e6953c061d7f0b3"
var TemporaryFlipKickData = "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000008cb6176addcca2e1d1ffe21bee464b72ee4cd8d00000000000000000000000038219779a699d67d7e7740b8c8f43d3e2dae218266616b6520696c6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a09200000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000005b69b8e7000000000000000000000000000000000000000000000000000000005b607e670000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca0000000000000000000000000000000000000000000000000000000000000032"
var TempBlockNumber = int64(10)
var TemporaryFlipKickBlockNumber = int64(TempBlockNumber)
var TemporaryFlipKickBlockHash = "0x32f8b12023b3a1b4c73f9a46da976931b0355714ada8b8044ebcb2cd295751a9"
var idString = "1"
var id, _ = new(big.Int).SetString(idString, 10)
var mom = "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d"
var vat = "0x38219779a699d67d7e7740b8c8f43d3e2dae2182"
var ilk = [32]byte{102, 97, 107, 101, 32, 105, 108, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
var lotString = "100"
var lot, _ = new(big.Int).SetString(lotString, 10)
var bidString = "0"
var bid = new(big.Int).SetBytes([]byte{0})
var guy = "0x64d922894153be9eef7b7218dc565d1d0ce2a092"
var gal = "0x07fa9ef6609ca7921112231f8f195138ebba2977"
var end = int64(1533655271)
var era = int64(1533050471)
var lad = "0x7340e006f4135ba6970d43bf43d88dcad4e7a8ca"
var tabString = "50"
var tab, _ = new(big.Int).SetString(tabString, 10)
var EthFlipKickLog = types.Log{
Address: common.HexToAddress(TemporaryFlipAddress),
Topics: []common.Hash{common.HexToHash(every_block.FlipKickSignature)},
Data: hexutil.MustDecode(TemporaryFlipKickData),
BlockNumber: uint64(TempBlockNumber),
TxHash: common.HexToHash(TemporaryFlipKickTransaction),
TxIndex: 0,
BlockHash: common.HexToHash(TemporaryFlipKickBlockHash),
Index: 0,
Removed: false,
}
var FlipKickEntity = every_block.FlipKickEntity{
Id: id,
Mom: common.HexToAddress(mom),
Vat: common.HexToAddress(vat),
Ilk: ilk,
Lot: lot,
Bid: bid,
Guy: common.HexToAddress(guy),
Gal: common.HexToAddress(gal),
End: big.NewInt(end),
Era: big.NewInt(era),
Lad: common.HexToAddress(lad),
Tab: tab,
}
var FlipKickModel = every_block.FlipKickModel{
Id: idString,
Mom: mom,
Vat: vat,
Ilk: "0x" + common.Bytes2Hex(ilk[:]),
Lot: lotString,
Bid: bidString,
Guy: guy,
Gal: gal,
End: time.Unix(end, 0),
Era: time.Unix(era, 0),
Lad: lad,
Tab: tabString,
}
type FlipKickDBRow struct {
DbID int64 `db:"db_id"`
HeaderId int64 `db:"header_id"`
every_block.FlipKickModel
}

View File

@ -0,0 +1,105 @@
// 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 test_data
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/libraries/maker/every_block"
"github.com/vulcanize/vulcanizedb/pkg/core"
)
type MockLogFetcher struct {
FetchedContractAddress string
FetchedTopics [][]common.Hash
FetchedBlocks []int64
FetcherError error
FetchedLogs []types.Log
}
func (mlf *MockLogFetcher) FetchLogs(contractAddress string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error) {
mlf.FetchedContractAddress = contractAddress
mlf.FetchedTopics = topics
mlf.FetchedBlocks = append(mlf.FetchedBlocks, blockNumber)
return mlf.FetchedLogs, mlf.FetcherError
}
func (mlf *MockLogFetcher) SetFetcherError(err error) {
mlf.FetcherError = err
}
func (mlf *MockLogFetcher) SetFetchedLogs(logs []types.Log) {
mlf.FetchedLogs = logs
}
type MockFlipKickConverter struct {
ConverterContract string
ConverterAbi string
LogsToConvert []types.Log
EntitiesToConvert []every_block.FlipKickEntity
ConverterError error
}
func (mfkc *MockFlipKickConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (*every_block.FlipKickEntity, error) {
mfkc.ConverterContract = contractAddress
mfkc.ConverterAbi = contractAbi
mfkc.LogsToConvert = append(mfkc.LogsToConvert, ethLog)
return &FlipKickEntity, mfkc.ConverterError
}
func (mfkc *MockFlipKickConverter) ToModel(flipKick every_block.FlipKickEntity) (every_block.FlipKickModel, error) {
mfkc.EntitiesToConvert = append(mfkc.EntitiesToConvert, flipKick)
return FlipKickModel, nil
}
func (mfkc *MockFlipKickConverter) SetConverterError(err error) {
mfkc.ConverterError = err
}
type MockFlipKickRepository struct {
HeaderIds []int64
HeadersToReturn []core.Header
StartingBlockNumber int64
EndingBlockNumber int64
FlipKicksCreated []every_block.FlipKickModel
CreateRecordError error
MissingHeadersError error
}
func (mfkr *MockFlipKickRepository) Create(headerId int64, flipKick every_block.FlipKickModel) error {
mfkr.HeaderIds = append(mfkr.HeaderIds, headerId)
mfkr.FlipKicksCreated = append(mfkr.FlipKicksCreated, flipKick)
return mfkr.CreateRecordError
}
func (mfkr *MockFlipKickRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
mfkr.StartingBlockNumber = startingBlockNumber
mfkr.EndingBlockNumber = endingBlockNumber
return mfkr.HeadersToReturn, mfkr.MissingHeadersError
}
func (mfkr *MockFlipKickRepository) SetHeadersToReturn(headers []core.Header) {
mfkr.HeadersToReturn = headers
}
func (mfkr *MockFlipKickRepository) SetCreateRecordError(err error) {
mfkr.CreateRecordError = err
}
func (mfkr *MockFlipKickRepository) SetMissingHeadersError(err error) {
mfkr.MissingHeadersError = err
}

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[{"logIndex":"0x0","transactionIndex":"0x0","transactionHash":"0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191","blockHash":"0x59d43865d29b1ddf0baff73a78e06849c015249fd1884bd5a93e83d5be9c05dd","blockNumber":"0xa","address":"0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d","data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000008cb6176addcca2e1d1ffe21bee464b72ee4cd8d00000000000000000000000038219779a699d67d7e7740b8c8f43d3e2dae218266616b6520696c6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a09200000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000005b69b8e7000000000000000000000000000000000000000000000000000000005b607e670000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca0000000000000000000000000000000000000000000000000000000000000032","topics":["0xc2d733c352a325d6ecf23d1cf0a189dbcc236b0636388b8c5e6953c061d7f0b3"],"type":"mined"}]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
11

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0xafc7c6a8161d69dc1b082bbf799d38f88c2f251a7504b87039b2a4f682cbf323","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x","gasLimit":"0x6691b7","gasUsed":"0x","timestamp":"0x5b607bcc","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[],"uncleHeaders":[]}

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0x92df7e05e7e8c221851b23ef4ce61671ef7b2df3cbd1b5fb0b5b4735803484d2","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x1cf5126fea51794b0db1435d14bd933683c230379908b9899391e70c1bdfbe14","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x01","gasLimit":"0x6691b7","gasUsed":"0x043bd6","timestamp":"0x5b607bda","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[{"nonce":"0x","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0x","value":"0x","data":"0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f8806100606000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100aa5780638da5cb5b146100d5578063fdacd5761461012c575b600080fd5b34801561007357600080fd5b506100a8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610159565b005b3480156100b657600080fd5b506100bf610241565b6040518082815260200191505060405180910390f35b3480156100e157600080fd5b506100ea610247565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b506101576004803603810190808035906020019092919050505061026c565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561023d578190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561022457600080fd5b505af1158015610238573d6000803e3d6000fd5b505050505b5050565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102c957806001819055505b505600a165627a7a72305820167320a3f0aefab2d9d7492779c69a7f6bbea970d8290e17d3631fbed9ad93540029","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0xd484799e4f3a24c0e83d7210ae6936700f2da07ddc3cb7191b06a5e20b10fb61"}],"uncleHeaders":[]}

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0x3a1b9dd73229701cf992f80bc79ef5c00a9254054fa4afbcb1a619a6af48aa44","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x50b3886d0b373a1bec1077a101dfbf8cdf97373f7698dc90befabe95a62c18d0","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000020000000000000000080000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000","difficulty":"0x","number":"0x0a","gasLimit":"0x6691b7","gasUsed":"0x027c77","timestamp":"0x5b607e67","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[{"nonce":"0x","gasPrice":"0x01","gasLimit":"0x44aa20","to":"0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d","value":"0x","data":"0x351de6000000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca00000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000","v":"0x1c","r":"0x","s":"0x","from":"0x64d922894153be9eef7b7218dc565d1d0ce2a092","hash":"0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191"}],"uncleHeaders":[]}

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0x7e8df460b9fe6f779d308571d81629f57e66648907f6c97ba7712d15a553087a","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x3ad54ef88f031c776dcc858e4339ee689f634fb929d7ac5d9ceec36c15b2779e","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x02","gasLimit":"0x6691b7","gasUsed":"0xa418","timestamp":"0x5b607bda","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[{"nonce":"0x01","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0xfc0ba85028256ef48f5ba64dd65dc258988955f6","value":"0x","data":"0xfdacd5760000000000000000000000000000000000000000000000000000000000000001","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0xc0bdfdb15c288d6a7b0af865d953677c4818c6655d26631bd7b840e9cfb2d668"}],"uncleHeaders":[]}

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0xa991182133d4d762d84b3213e93f29caf30a8c68552f95830a934b886560762a","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x3ec08de1b6fc2f56324ce3a496f6945898622e7b8e875feb74d0578b18f6730c","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x03","gasLimit":"0x6691b7","gasUsed":"0x010cba","timestamp":"0x5b607bdb","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[{"nonce":"0x02","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0x","value":"0x","data":"0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820562865e6c1f558e8a54735c0ff54b7f6a1fbc65c540a84c894f17a5fec64110d0029","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0x9430a6e3c1665c19dfe6e55eba73ae209d256b17d8f2ea63acb9bdf23144f0a9"}],"uncleHeaders":[]}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"header":{"parentHash":"0x82ddc58a8608bdac6cf29a962dabd34e0f3e1b8c76bf14459f8a1c9bdb1a9789","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x2755f446d0c4053242e02044d205ff5f10f34d7eada2b8170e32dbe7ce649b54","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x05","gasLimit":"0x6691b7","gasUsed":"0x6980","timestamp":"0x5b607bdb","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x"},"transactions":[{"nonce":"0x04","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0xfc0ba85028256ef48f5ba64dd65dc258988955f6","value":"0x","data":"0xfdacd5760000000000000000000000000000000000000000000000000000000000000002","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0x2194da14a0d4be36fb809efd3f9f426bf60842dbf244788d0a84b894b3e6bd49"}],"uncleHeaders":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
11

View File

@ -0,0 +1 @@
{"transactionHash":"0x082845bda230c63db3069f3568ef138653aed0beaf8791ca1644b0d2e62b4b62","transactionIndex":"0x0","blockHash":"0x3a1b9dd73229701cf992f80bc79ef5c00a9254054fa4afbcb1a619a6af48aa44","blockNumber":"0x9","gasUsed":"0x1e6e49","cumulativeGasUsed":"0x1e6e49","contractAddress":"0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x194d05ed98adbaab385bf58f5a2b6aa2d53e5a083e156ab4115940687baf2d48","transactionIndex":"0x0","blockHash":"0xea660033df6296bce69b24ca2e91556f1d9c5f6c6e9c4ee5ea9877426b6fc893","blockNumber":"0x6","gasUsed":"0xbabc2","cumulativeGasUsed":"0xbabc2","contractAddress":"0xff3f2400f1600f3f493a9a92704a29b96795af1a","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x2194da14a0d4be36fb809efd3f9f426bf60842dbf244788d0a84b894b3e6bd49","transactionIndex":"0x0","blockHash":"0xe3f5f15620f4599a82eba709537542c5db00c2f03f1863646bc2633f80b1a549","blockNumber":"0x5","gasUsed":"0x6980","cumulativeGasUsed":"0x6980","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x319b41551e19a365e1819fc312f1cd52e315c575d505c9fa90a748b7dab11eb9","transactionIndex":"0x0","blockHash":"0x4e22a16f36c4579b10db23891796b93ec0452791bf24426836837fc420bec9b7","blockNumber":"0x7","gasUsed":"0xfc1e5","cumulativeGasUsed":"0xfc1e5","contractAddress":"0x76189df410263ad1d9fe2f4af2eab3d24f1b6f41","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191","transactionIndex":"0x0","blockHash":"0x59d43865d29b1ddf0baff73a78e06849c015249fd1884bd5a93e83d5be9c05dd","blockNumber":"0xa","gasUsed":"0x27c77","cumulativeGasUsed":"0x27c77","contractAddress":null,"logs":[{"logIndex":"0x0","transactionIndex":"0x0","transactionHash":"0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191","blockHash":"0x59d43865d29b1ddf0baff73a78e06849c015249fd1884bd5a93e83d5be9c05dd","blockNumber":"0xa","address":"0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d","data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000008cb6176addcca2e1d1ffe21bee464b72ee4cd8d00000000000000000000000038219779a699d67d7e7740b8c8f43d3e2dae218266616b6520696c6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a09200000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000005b69b8e7000000000000000000000000000000000000000000000000000000005b607e670000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca0000000000000000000000000000000000000000000000000000000000000032","topics":["0xc2d733c352a325d6ecf23d1cf0a189dbcc236b0636388b8c5e6953c061d7f0b3"],"type":"mined"}],"status":"0x1","logsBloom":"0x00000000000000000020000000000000000080000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x7ba6513b8f9e12e3a82075c61b3c2848ebed77919cf0c158292cf32fafc55172","transactionIndex":"0x0","blockHash":"0x82ddc58a8608bdac6cf29a962dabd34e0f3e1b8c76bf14459f8a1c9bdb1a9789","blockNumber":"0x4","gasUsed":"0x18b018","cumulativeGasUsed":"0x18b018","contractAddress":"0x38219779a699d67d7e7740b8c8f43d3e2dae2182","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0x9430a6e3c1665c19dfe6e55eba73ae209d256b17d8f2ea63acb9bdf23144f0a9","transactionIndex":"0x0","blockHash":"0x2c3b96f821a6abe12061036d3f90e3a04f72eb3b06952a1b0d8916bff0103406","blockNumber":"0x3","gasUsed":"0x10cba","cumulativeGasUsed":"0x10cba","contractAddress":"0xa970ed54e41d9db6d91db5e7ff7a9451dad98993","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0xc0bdfdb15c288d6a7b0af865d953677c4818c6655d26631bd7b840e9cfb2d668","transactionIndex":"0x0","blockHash":"0xa991182133d4d762d84b3213e93f29caf30a8c68552f95830a934b886560762a","blockNumber":"0x2","gasUsed":"0xa418","cumulativeGasUsed":"0xa418","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0xceba2ca8e63611b307f222e9b97e1cbec800f6701ef4d8f6080edf0faa6b9732","transactionIndex":"0x0","blockHash":"0x76443e96ab64087485c83dcaf3ed15ad5303b23393957f075901dab7cdefdef8","blockNumber":"0x8","gasUsed":"0xe03c1","cumulativeGasUsed":"0xe03c1","contractAddress":"0x7dbda851034713f899a122f95860eaf707b9f833","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"transactionHash":"0xd484799e4f3a24c0e83d7210ae6936700f2da07ddc3cb7191b06a5e20b10fb61","transactionIndex":"0x0","blockHash":"0x7e8df460b9fe6f779d308571d81629f57e66648907f6c97ba7712d15a553087a","blockNumber":"0x1","gasUsed":"0x43bd6","cumulativeGasUsed":"0x43bd6","contractAddress":"0xfc0ba85028256ef48f5ba64dd65dc258988955f6","logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"nonce":"0x04","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0xfc0ba85028256ef48f5ba64dd65dc258988955f6","value":"0x","data":"0xfdacd5760000000000000000000000000000000000000000000000000000000000000002","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0x2194da14a0d4be36fb809efd3f9f426bf60842dbf244788d0a84b894b3e6bd49"}

View File

@ -0,0 +1 @@
{"nonce":"0x","gasPrice":"0x01","gasLimit":"0x44aa20","to":"0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d","value":"0x","data":"0x351de6000000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca00000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000","v":"0x1c","r":"0x","s":"0x","from":"0x64d922894153be9eef7b7218dc565d1d0ce2a092","hash":"0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191"}

View File

@ -0,0 +1 @@
{"nonce":"0x02","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0x","value":"0x","data":"0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820562865e6c1f558e8a54735c0ff54b7f6a1fbc65c540a84c894f17a5fec64110d0029","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0x9430a6e3c1665c19dfe6e55eba73ae209d256b17d8f2ea63acb9bdf23144f0a9"}

View File

@ -0,0 +1 @@
{"nonce":"0x01","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0xfc0ba85028256ef48f5ba64dd65dc258988955f6","value":"0x","data":"0xfdacd5760000000000000000000000000000000000000000000000000000000000000001","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0xc0bdfdb15c288d6a7b0af865d953677c4818c6655d26631bd7b840e9cfb2d668"}

View File

@ -0,0 +1 @@
{"nonce":"0x","gasPrice":"0x174876e800","gasLimit":"0x6691b7","to":"0x","value":"0x","data":"0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f8806100606000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100aa5780638da5cb5b146100d5578063fdacd5761461012c575b600080fd5b34801561007357600080fd5b506100a8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610159565b005b3480156100b657600080fd5b506100bf610241565b6040518082815260200191505060405180910390f35b3480156100e157600080fd5b506100ea610247565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b506101576004803603810190808035906020019092919050505061026c565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561023d578190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561022457600080fd5b505af1158015610238573d6000803e3d6000fd5b505050505b5050565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102c957806001819055505b505600a165627a7a72305820167320a3f0aefab2d9d7492779c69a7f6bbea970d8290e17d3631fbed9ad93540029","v":"0x1c","r":"0x","s":"0x","from":"0x8e84a1e068d77059cbe263c43ad0cdc130863313","hash":"0xd484799e4f3a24c0e83d7210ae6936700f2da07ddc3cb7191b06a5e20b10fb61"}

View File

@ -0,0 +1 @@
"0xf90131a02b90ac735ccaf20d1204ce987c10f24fa0ecf777dbe99525c0321a58f237aa2380a01b9a0ca00da4bf0c31264a2bf0a2352c41b0012d157942fcabc59e64f08ec8a2a09d284defeed07bc2b2d65d7d4ba14066c71072010c352566ceb6af2105001fa38080a074952353b0991411841541f86d37934e0d826eb7411a2420ea362466d8d60e03a0f39ba3ac12d2744dd608f89cb539b72a387a2e605dba7ad9a4e935486657e80ca0fdcb675a2fb7395ce85312eeaf38d612251395b4277a958c4a78cea448e07cc1a025fc93ab219268b7e46014c8ac580adba1ce1051d8cb8bcb1cd238f4187e577ba0b9b76c57e2bde1c38c34e662ada45402840f239a67bc577357a9dafce809946a80808080a0c03c348f717530216ab354ac3ef0e19e46c28ce0f78640f445e41e4e9b02d5ca80"

View File

@ -0,0 +1 @@
"0xf8f1a0422861bc32af762face51a81dfb4e3f2d563beb99ee972cf1fa30b944e6b85f580a01b9a0ca00da4bf0c31264a2bf0a2352c41b0012d157942fcabc59e64f08ec8a2808080a074952353b0991411841541f86d37934e0d826eb7411a2420ea362466d8d60e03a0a7e84e568d915220899cd49f84d03cadbba602e3e04546e2c18064dcb0517963a051e94f71fe2273409ef0acbc4986df7bb808426470a9871d1f6d3324b780c194a025fc93ab219268b7e46014c8ac580adba1ce1051d8cb8bcb1cd238f4187e577ba063a1b8e271db0ec0a1816192da83ae3bec40470b66f31d047ef4911d0106dde2808080808080"

View File

@ -0,0 +1 @@
"0xf90131a080b4053526aa3f9eeead723f413de9449aa4066e6d54c701ac5bd5a05db08bf980a01b9a0ca00da4bf0c31264a2bf0a2352c41b0012d157942fcabc59e64f08ec8a2a09d284defeed07bc2b2d65d7d4ba14066c71072010c352566ceb6af2105001fa38080a074952353b0991411841541f86d37934e0d826eb7411a2420ea362466d8d60e03a0f39ba3ac12d2744dd608f89cb539b72a387a2e605dba7ad9a4e935486657e80ca0b8a4ccd79e4c55573c4c1909205f8a64815b241b68749290e126968a01a55296a025fc93ab219268b7e46014c8ac580adba1ce1051d8cb8bcb1cd238f4187e577ba0b9b76c57e2bde1c38c34e662ada45402840f239a67bc577357a9dafce809946a80808080a0b07a87e464ce02c066bb930db0ad6af18367210d9660609b5ecf4a6acb1e0ab380"

View File

@ -0,0 +1 @@
"0xf85120b84ef84c80887d705cb8966c4000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"

View File

@ -0,0 +1 @@
"0xf866943e84a1e068d77059cbe263c43ad0cdc130863313b84ff84d05890568f5064263e60000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"

View File

@ -0,0 +1 @@
"0xf851a0d8592c6f97b855e192b45cbc3a21093b529abc9cca3c368066d44aa31c9f0a57a034d4377e4f0dee74f4a49f6c09d66f6d4ff253d260d052e8d5ffe022965d6ffc808080808080808080808080808080"

View File

@ -0,0 +1 @@
"0xf90131a0e471b75d1693dfa4458588ca431b54af9320eca119ece050d55e1b05a94bad2480a01b9a0ca00da4bf0c31264a2bf0a2352c41b0012d157942fcabc59e64f08ec8a2a09d284defeed07bc2b2d65d7d4ba14066c71072010c352566ceb6af2105001fa38080a074952353b0991411841541f86d37934e0d826eb7411a2420ea362466d8d60e03a0d35dc35858f8b26ca6aca1a7801c782bb905b339c40e2f4d7fa9bbb6e60f2919a0ab6df9bdf417e2156e3d5b8fe119c9f9366e0fb63b6e79c6840068695a6d3b47a025fc93ab219268b7e46014c8ac580adba1ce1051d8cb8bcb1cd238f4187e577ba0b9b76c57e2bde1c38c34e662ada45402840f239a67bc577357a9dafce809946a80808080a0b07a87e464ce02c066bb930db0ad6af18367210d9660609b5ecf4a6acb1e0ab380"

View File

@ -0,0 +1 @@
"0xf842a01000000000000000000000000000000000000000000000000000000000000000a066c5d0a6016165e537ac63b121df2d074c649a16b50ca7a2839abc5eb3894a9a"

View File

@ -0,0 +1 @@
"0xf90111a08202796f16ed68ec4c55687dd91c9eaf8eb1506c93c66179b72255e15104f292a05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554a808080808080808080"

View File

@ -0,0 +1 @@
"0xf59310000000000000000000000000000000000000a0fb53e64824f62daa3a1598b6864c077c8b3feafa8d6f93bb5185dcd52a55f4b5"

Some files were not shown because too many files have changed in this diff Show More