diff --git a/.circleci/config.yml b/.circleci/config.yml index 331aa6d072..39242f496c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,3 +16,5 @@ jobs: - checkout # check out source code to working directory - run: command: make bor + - run: + command: make test diff --git a/Makefile b/Makefile index 9f863193ea..93a7a3ee2a 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ ios: @echo "Done building." @echo "Import \"$(GOBIN)/bor.framework\" to use the library." -test: all - build/env.sh go run build/ci.go test +test: bor + go test github.com/maticnetwork/bor/consensus/bor_test lint: ## Run linters. build/env.sh go run build/ci.go lint diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 0daf9353b0..d84288d429 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -10,7 +10,7 @@ import ( "io" "math" "math/big" - "net/http" + "sort" "strconv" "strings" @@ -243,7 +243,7 @@ type Bor struct { ethAPI *ethapi.PublicBlockChainAPI validatorSetABI abi.ABI stateReceiverABI abi.ABI - httpClient http.Client + HeimdallClient IHeimdallClient // The fields below are for testing only fakeDiff bool // Skip difficulty verifications @@ -268,6 +268,8 @@ func New( signatures, _ := lru.NewARC(inmemorySignatures) vABI, _ := abi.JSON(strings.NewReader(validatorsetABI)) sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI)) + heimdallClient, _ := NewHeimdallClient(chainConfig.Bor.Heimdall) + c := &Bor{ chainConfig: chainConfig, config: borConfig, @@ -277,9 +279,7 @@ func New( signatures: signatures, validatorSetABI: vABI, stateReceiverABI: sABI, - httpClient: http.Client{ - Timeout: time.Duration(5 * time.Second), - }, + HeimdallClient: heimdallClient, } return c @@ -563,7 +563,6 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare if err != nil { return err } - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { return errUnauthorizedSigner } @@ -662,15 +661,15 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error { // rewards given. func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { // commit span - if header.Number.Uint64()%c.config.Sprint == 0 { - cx := chainContext{Chain: chain, Bor: c} + headerNumber := header.Number.Uint64() + if headerNumber%c.config.Sprint == 0 { + cx := chainContext{Chain: chain, Bor: c} // check and commit span if err := c.checkAndCommitSpan(state, header, cx); err != nil { log.Error("Error while committing span", "error", err) return } - // commit statees if err := c.CommitStates(state, header, cx); err != nil { log.Error("Error while committing states", "error", err) @@ -986,33 +985,42 @@ func (c *Bor) checkAndCommitSpan( header *types.Header, chain core.ChainContext, ) error { + headerNumber := header.Number.Uint64() pending := false var span *Span = nil - var wg sync.WaitGroup - wg.Add(1) + errors := make(chan error) go func() { - pending, _ = c.isSpanPending(header.Number.Uint64()) - wg.Done() + var err error + pending, err = c.isSpanPending(headerNumber - 1) + errors <- err }() - wg.Add(1) go func() { - span, _ = c.GetCurrentSpan(header.Number.Uint64() - 1) - wg.Done() + var err error + span, err = c.GetCurrentSpan(headerNumber - 1) + errors <- err }() - wg.Wait() + var err error + for i := 0; i < 2; i++ { + err = <-errors + if err != nil { + close(errors) + return err + } + } + close(errors) // commit span if there is new span pending or span is ending or end block is not set - if pending || c.needToCommitSpan(span, header) { - err := c.commitSpan(span, state, header, chain) + if pending || c.needToCommitSpan(span, headerNumber) { + err := c.fetchAndCommitSpan(span.ID+1, state, header, chain) return err } return nil } -func (c *Bor) needToCommitSpan(span *Span, header *types.Header) bool { +func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool { // if span is nil if span == nil { return false @@ -1024,21 +1032,21 @@ func (c *Bor) needToCommitSpan(span *Span, header *types.Header) bool { } // if current block is first block of last sprint in current span - h := header.Number.Uint64() - if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == h { + if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == headerNumber { return true } return false } -func (c *Bor) commitSpan( - span *Span, +func (c *Bor) fetchAndCommitSpan( + newSpanID uint64, state *state.StateDB, header *types.Header, chain core.ChainContext, ) error { - response, err := FetchFromHeimdallWithRetry(c.httpClient, c.chainConfig.Bor.Heimdall, "bor", "span", strconv.FormatUint(span.ID+1, 10)) + response, err := c.HeimdallClient.FetchWithRetry("bor", "span", strconv.FormatUint(newSpanID, 10)) + if err != nil { return err } @@ -1166,7 +1174,7 @@ func (c *Bor) CommitStates( // itereate through state ids for _, stateID := range stateIds { // fetch from heimdall - response, err := FetchFromHeimdallWithRetry(c.httpClient, c.chainConfig.Bor.Heimdall, "clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10)) + response, err := c.HeimdallClient.FetchWithRetry("clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10)) if err != nil { return err } @@ -1218,6 +1226,44 @@ func (c *Bor) CommitStates( return nil } +func (c *Bor) SetHeimdallClient(h IHeimdallClient) { + c.HeimdallClient = h +} + +func (c *Bor) IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool { + header := chain.CurrentHeader() + validators, err := c.GetCurrentValidators(header.Number.Uint64(), header.Number.Uint64()+1) + if err != nil { + log.Error("Failed fetching snapshot", err) + return false + } + + isValidator := false + for _, validator := range validators { + if bytes.Compare(validator.Address.Bytes(), from.Bytes()) == 0 { + isValidator = true + break + } + } + + return isValidator && (isProposeSpanAction(tx, chain.Config().Bor.ValidatorContract) || + isProposeStateAction(tx, chain.Config().Bor.StateReceiverContract)) +} + +func isProposeSpanAction(tx *types.Transaction, validatorContract string) bool { + // keccak256('proposeSpan()').slice(0, 4) + proposeSpanSig, _ := hex.DecodeString("4b0e4d17") + return bytes.Compare(proposeSpanSig, tx.Data()[:4]) == 0 && + tx.To().String() == validatorContract +} + +func isProposeStateAction(tx *types.Transaction, stateReceiverContract string) bool { + // keccak256('proposeState(uint256)').slice(0, 4) + proposeStateSig, _ := hex.DecodeString("ede01f17") + return bytes.Compare(proposeStateSig, tx.Data()[:4]) == 0 && + tx.To().String() == stateReceiverContract +} + // // Private methods // diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go index a312959132..6129037fc3 100644 --- a/consensus/bor/rest.go +++ b/consensus/bor/rest.go @@ -19,9 +19,61 @@ type ResponseWithHeight struct { Result json.RawMessage `json:"result"` } +type IHeimdallClient interface { + Fetch(paths ...string) (*ResponseWithHeight, error) + FetchWithRetry(paths ...string) (*ResponseWithHeight, error) +} + +type HeimdallClient struct { + u *url.URL + client http.Client +} + +func NewHeimdallClient(urlString string) (*HeimdallClient, error) { + u, err := url.Parse(urlString) + if err != nil { + return nil, err + } + + h := &HeimdallClient{ + u: u, + client: http.Client{ + Timeout: time.Duration(5 * time.Second), + }, + } + return h, nil +} + +func (h *HeimdallClient) Fetch(paths ...string) (*ResponseWithHeight, error) { + for _, e := range paths { + if e != "" { + h.u.Path = path.Join(h.u.Path, e) + } + } + return h.internalFetch() +} + +// FetchWithRetry returns data from heimdall with retry +func (h *HeimdallClient) FetchWithRetry(paths ...string) (*ResponseWithHeight, error) { + for _, e := range paths { + if e != "" { + h.u.Path = path.Join(h.u.Path, e) + } + } + + for { + res, err := h.internalFetch() + if err == nil && res != nil { + return res, nil + } + log.Info("Retrying again in 5 seconds for next Heimdall span", "path", h.u.Path) + time.Sleep(5 * time.Second) + } +} + // internal fetch method -func internalFetch(client http.Client, u *url.URL) (*ResponseWithHeight, error) { - res, err := client.Get(u.String()) +func (h *HeimdallClient) internalFetch() (*ResponseWithHeight, error) { + res, err := h.client.Get(h.u.String()) if err != nil { return nil, err } @@ -46,42 +98,3 @@ func internalFetch(client http.Client, u *url.URL) (*ResponseWithHeight, error) return &response, nil } - -// FetchFromHeimdallWithRetry returns data from heimdall with retry -func FetchFromHeimdallWithRetry(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) { - u, err := url.Parse(urlString) - if err != nil { - return nil, err - } - - for _, e := range paths { - if e != "" { - u.Path = path.Join(u.Path, e) - } - } - - for { - res, err := internalFetch(client, u) - if err == nil && res != nil { - return res, nil - } - log.Info("Retrying again in 5 seconds for next Heimdall span", "path", u.Path) - time.Sleep(5 * time.Second) - } -} - -// FetchFromHeimdall returns data from heimdall -func FetchFromHeimdall(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) { - u, err := url.Parse(urlString) - if err != nil { - return nil, err - } - - for _, e := range paths { - if e != "" { - u.Path = path.Join(u.Path, e) - } - } - - return internalFetch(client, u) -} diff --git a/consensus/bor_test/bor_test.go b/consensus/bor_test/bor_test.go new file mode 100644 index 0000000000..88eb9245b5 --- /dev/null +++ b/consensus/bor_test/bor_test.go @@ -0,0 +1,253 @@ +package bor_test + +import ( + "encoding/hex" + "encoding/json" + "io/ioutil" + "math/big" + "testing" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/consensus/bor" + "github.com/maticnetwork/bor/core" + "github.com/maticnetwork/bor/core/rawdb" + "github.com/maticnetwork/bor/core/state" + "github.com/maticnetwork/bor/crypto/secp256k1" + "github.com/stretchr/testify/assert" + + "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/crypto" + "github.com/maticnetwork/bor/eth" + + "github.com/maticnetwork/bor/ethdb" + "github.com/maticnetwork/bor/mocks" + "github.com/maticnetwork/bor/node" +) + +var ( + extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal + privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7 +) + +type initializeData struct { + genesis *core.Genesis + ethereum *eth.Ethereum +} + +func TestCommitSpan(t *testing.T) { + init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) + chain := init.ethereum.BlockChain() + engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + + // Mock HeimdallClient.FetchWithRetry to return span data from span.json + res, heimdallSpan := loadSpanFromFile(t) + h := &mocks.IHeimdallClient{} + h.On("FetchWithRetry", "bor", "span", "1"). + Return(res, nil). + Times(2) // both FinalizeAndAssemble and chain.InsertChain call HeimdallClient.FetchWithRetry. @todo Investigate this in depth + _bor.SetHeimdallClient(h) + + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + // Build 1st block's header + header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) + + statedb, err := chain.State() + if err != nil { + t.Fatalf("%s", err) + } + + _key, _ := hex.DecodeString(privKey) + insertNewBlock(t, _bor, chain, header, statedb, _key) + + assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 2)) + validators, err := _bor.GetCurrentValidators(1, 256) // new span starts at 256 + if err != nil { + t.Fatalf("%s", err) + } + + assert.Equal(t, len(validators), 3) + for i, validator := range validators { + assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes()) + assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower) + } +} + +func TestIsValidatorAction(t *testing.T) { + init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) + chain := init.ethereum.BlockChain() + engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + + proposeStateData, _ := hex.DecodeString("ede01f170000000000000000000000000000000000000000000000000000000000000000") + proposeSpanData, _ := hex.DecodeString("4b0e4d17") + var tx *types.Transaction + tx = types.NewTransaction( + 0, + common.HexToAddress(chain.Config().Bor.StateReceiverContract), + big.NewInt(0), 0, big.NewInt(0), + proposeStateData, + ) + assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) + + tx = types.NewTransaction( + 0, + common.HexToAddress(chain.Config().Bor.ValidatorContract), + big.NewInt(0), 0, big.NewInt(0), + proposeSpanData, + ) + assert.True(t, _bor.IsValidatorAction(chain, addr, tx)) + + res, heimdallSpan := loadSpanFromFile(t) + h := &mocks.IHeimdallClient{} + h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil) + _bor.SetHeimdallClient(h) + + // Build 1st block's header + db := init.ethereum.ChainDb() + block := init.genesis.ToBlock(db) + + header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) + statedb, err := chain.State() + if err != nil { + t.Fatalf("%s", err) + } + + _key, _ := hex.DecodeString(privKey) + insertNewBlock(t, _bor, chain, header, statedb, _key) + block = types.NewBlockWithHeader(header) + + var headers []*types.Header + for i := int64(2); i <= 255; i++ { + header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period) + headers = append(headers, header) + block = types.NewBlockWithHeader(header) + } + t.Logf("inserting %v headers", len(headers)) + if _, err := chain.InsertHeaderChain(headers, 0); err != nil { + t.Fatalf("%s", err) + } + + for _, validator := range heimdallSpan.SelectedProducers { + _addr := validator.Address + tx = types.NewTransaction( + 0, + common.HexToAddress(chain.Config().Bor.StateReceiverContract), + big.NewInt(0), 0, big.NewInt(0), + proposeStateData, + ) + assert.True(t, _bor.IsValidatorAction(chain, _addr, tx)) + + tx = types.NewTransaction( + 0, + common.HexToAddress(chain.Config().Bor.ValidatorContract), + big.NewInt(0), 0, big.NewInt(0), + proposeSpanData, + ) + assert.True(t, _bor.IsValidatorAction(chain, _addr, tx)) + } +} + +func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { + genesisData, err := ioutil.ReadFile("genesis.json") + if err != nil { + t.Fatalf("%s", err) + } + gen := &core.Genesis{} + if err := json.Unmarshal(genesisData, gen); err != nil { + t.Fatalf("%s", err) + } + ethConf := ð.Config{ + Genesis: gen, + } + ethConf.Genesis.MustCommit(db) + + // Create a temporary storage for the node keys and initialize it + workspace, err := ioutil.TempDir("", "console-tester-") + if err != nil { + t.Fatalf("failed to create temporary keystore: %v", err) + } + + // Create a networkless protocol stack and start an Ethereum service within + stack, err := node.New(&node.Config{DataDir: workspace, UseLightweightKDF: true, Name: "console-tester"}) + if err != nil { + t.Fatalf("failed to create node: %v", err) + } + err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + s, err := eth.New(ctx, ethConf) + return s, err + }) + if err != nil { + t.Fatalf("failed to register Ethereum protocol: %v", err) + } + + // Start the node and assemble the JavaScript console around it + if err = stack.Start(); err != nil { + t.Fatalf("failed to start test stack: %v", err) + } + _, err = stack.Attach() + if err != nil { + t.Fatalf("failed to attach to node: %v", err) + } + + var ethereum *eth.Ethereum + stack.Service(ðereum) + ethConf.Genesis.MustCommit(ethereum.ChainDb()) + return &initializeData{ + genesis: gen, + ethereum: ethereum, + } +} + +func insertNewBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, header *types.Header, statedb *state.StateDB, privKey []byte) { + _, err := _bor.FinalizeAndAssemble(chain, header, statedb, nil, nil, nil) + if err != nil { + t.Fatalf("%s", err) + } + + sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), privKey) + if err != nil { + t.Fatalf("%s", err) + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + + block := types.NewBlockWithHeader(header) + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + t.Fatalf("%s", err) + } +} + +func buildMinimalNextHeader(t *testing.T, block *types.Block, period uint64) *types.Header { + header := block.Header() + header.Number.Add(header.Number, big.NewInt(1)) + header.ParentHash = block.Hash() + header.Time += (period + 1) + header.Extra = make([]byte, 97) // vanity (32) + extraSeal (65) + _key, _ := hex.DecodeString(privKey) + sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), _key) + if err != nil { + t.Fatalf("%s", err) + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + return header +} + +func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) { + spanData, err := ioutil.ReadFile("span.json") + if err != nil { + t.Fatalf("%s", err) + } + res := &bor.ResponseWithHeight{} + if err := json.Unmarshal(spanData, res); err != nil { + t.Fatalf("%s", err) + } + + heimdallSpan := &bor.HeimdallSpan{} + if err := json.Unmarshal(res.Result, heimdallSpan); err != nil { + t.Fatalf("%s", err) + } + return res, heimdallSpan +} diff --git a/consensus/bor_test/genesis.json b/consensus/bor_test/genesis.json new file mode 100644 index 0000000000..737cb600dd --- /dev/null +++ b/consensus/bor_test/genesis.json @@ -0,0 +1,47 @@ +{ + "config": { + "chainId": 15001, + "homesteadBlock": 1, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "bor": { + "period": 1, + "producerDelay": 4, + "sprint": 1, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "heimdall": "http://localhost:1317" + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106102115760003560e01c806365b3a1e211610125578063b2472431116100ad578063d0504f891161007c578063d0504f89146106af578063d5b844eb146106cb578063dcf2793a146106e9578063e3b7c9241461071b578063f59cf5651461073957610211565b8063b247243114610612578063b71d7a6914610630578063b7ab4db514610660578063c1b3c9191461067f57610211565b806370ba5707116100f457806370ba57071461055657806398ab2b62146105865780639d11b807146105a4578063ae756451146105d4578063af26aa96146105f257610211565b806365b3a1e2146104c957806366332354146104e8578063687a9bd61461050657806369c49fac1461053857610211565b806335ddfeea116101a85780634b0e4d17116101775780634b0e4d17146104215780634dbc959f1461042b57806355614fcc14610449578063582a8d081461047957806360c8614d146104a957610211565b806335ddfeea1461037357806343ee8213146103a357806344c15cb1146103c157806344d6528f146103f157610211565b806323f2a73f116101e457806323f2a73f146102c55780632de3a180146102f55780632eddf352146103255780633434735f1461035557610211565b8063047a6c5b146102165780630c35b1cb146102485780631270b5741461027957806323c2a2b4146102a9575b600080fd5b610230600480360361022b9190810190612e7e565b61076b565b60405161023f93929190613903565b60405180910390f35b610262600480360361025d9190810190612e7e565b6107c2565b6040516102709291906136c4565b60405180910390f35b610293600480360361028e9190810190612ea7565b61099e565b6040516102a091906136fb565b60405180910390f35b6102c360048036036102be9190810190612f86565b610af6565b005b6102df60048036036102da9190810190612ea7565b611177565b6040516102ec91906136fb565b60405180910390f35b61030f600480360361030a9190810190612d18565b6112cf565b60405161031c9190613716565b60405180910390f35b61033f600480360361033a9190810190612e7e565b611350565b60405161034c91906138b1565b60405180910390f35b61035d611481565b60405161036a91906136a9565b60405180910390f35b61038d60048036036103889190810190612d54565b611499565b60405161039a91906136fb565b60405180910390f35b6103ab611564565b6040516103b89190613716565b60405180910390f35b6103db60048036036103d69190810190612ee3565b61157b565b6040516103e891906138b1565b60405180910390f35b61040b60048036036104069190810190612ea7565b611663565b6040516104189190613896565b60405180910390f35b6104296117cc565b005b610433611828565b60405161044091906138b1565b60405180910390f35b610463600480360361045e9190810190612c9d565b611838565b60405161047091906136fb565b60405180910390f35b610493600480360361048e9190810190612cc6565b611852565b6040516104a09190613716565b60405180910390f35b6104b16118d0565b6040516104c093929190613903565b60405180910390f35b6104d1611944565b6040516104df9291906136c4565b60405180910390f35b6104f0611a34565b6040516104fd91906138b1565b60405180910390f35b610520600480360361051b9190810190612f4a565b611a39565b60405161052f939291906138cc565b60405180910390f35b610540611a9d565b60405161054d91906136fb565b60405180910390f35b610570600480360361056b9190810190612c9d565b611ab4565b60405161057d91906136fb565b60405180910390f35b61058e611ace565b60405161059b9190613716565b60405180910390f35b6105be60048036036105b99190810190612e7e565b611ae5565b6040516105cb91906138b1565b60405180910390f35b6105dc611c16565b6040516105e99190613716565b60405180910390f35b6105fa611c2d565b60405161060993929190613903565b60405180910390f35b61061a611c8e565b60405161062791906138b1565b60405180910390f35b61064a60048036036106459190810190612e7e565b611c94565b60405161065791906138b1565b60405180910390f35b610668611d94565b6040516106769291906136c4565b60405180910390f35b61069960048036036106949190810190612e7e565b611da8565b6040516106a691906138b1565b60405180910390f35b6106c960048036036106c49190810190612dbb565b611dc9565b005b6106d361201f565b6040516106e0919061393a565b60405180910390f35b61070360048036036106fe9190810190612f4a565b612024565b604051610712939291906138cc565b60405180910390f35b610723612088565b60405161073091906138b1565b60405180910390f35b610753600480360361074e9190810190612e7e565b61209a565b60405161076293929190613903565b60405180910390f35b60008060006004600085815260200190815260200160002060000154600460008681526020019081526020016000206001015460046000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107de576107d5611944565b91509150610999565b60006107e984611c94565b9050606060036000838152602001908152602001600020805490506040519080825280602002602001820160405280156108325781602001602082028038833980820191505090505b5090506060600360008481526020019081526020016000208054905060405190808252806020026020018201604052801561087c5781602001602082028038833980820191505090505b50905060008090505b600360008581526020019081526020016000208054905081101561098e576003600085815260200190815260200160002081815481106108c157fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168382815181106108ff57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060036000858152602001908152602001600020818154811061095757fe5b90600052602060002090600302016001015482828151811061097557fe5b6020026020010181815250508080600101915050610885565b508181945094505050505b915091565b6000606060036000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a71578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906109d5565b50505050905060008090505b8151811015610ae9578373ffffffffffffffffffffffffffffffffffffffff16828281518110610aa957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610adc57600192505050610af0565b8080600101915050610a7d565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b4257600080fd5b6000610b4c611828565b90506000811415610b6057610b5f6120c4565b5b610b746001826123f090919063ffffffff16565b8814610bb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bac906137b6565b60405180910390fd5b868611610bf7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bee90613816565b60405180910390fd5b6000805460018989030181610c0857fe5b0614610c49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c40906137f6565b60405180910390fd5b8660046000838152602001908152602001600020600101541115610ca2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9990613776565b60405180910390fd5b6000600460008a81526020019081526020016000206000015414610cfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf2906137d6565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600460008a815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060058890806001815401808255809150509060018203906000526020600020016000909192909190915055506000600260008a815260200190815260200160002081610d969190612a97565b506000600360008a815260200190815260200160002081610db79190612a97565b506060610e0f610e0a87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b8151811015610f83576060610e3e838381518110610e3157fe5b602002602001015161243d565b9050600260008c81526020019081526020016000208054809190600101610e659190612a97565b506040518060600160405280610e8e83600081518110610e8157fe5b602002602001015161251a565b8152602001610eb083600181518110610ea357fe5b602002602001015161251a565b8152602001610ed283600281518110610ec557fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600260008d81526020019081526020016000208381548110610f0957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610e17565b506060610fdb610fd686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b815181101561114f57606061100a838381518110610ffd57fe5b602002602001015161243d565b9050600360008d815260200190815260200160002080548091906001016110319190612a97565b50604051806060016040528061105a8360008151811061104d57fe5b602002602001015161251a565b815260200161107c8360018151811061106f57fe5b602002602001015161251a565b815260200161109e8360028151811061109157fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600360008e815260200190815260200160002083815481106110d557fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fe3565b506000600160006101000a81548160ff02191690831515021790555050505050505050505050565b6000606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561124a578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906111ae565b50505050905060008090505b81518110156112c2578373ffffffffffffffffffffffffffffffffffffffff1682828151811061128257fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112b5576001925050506112c9565b8080600101915050611256565b5060009150505b92915050565b60006002600160f81b84846040516020016112ec93929190613616565b6040516020818303038152906040526040516113089190613653565b602060405180830381855afa158015611325573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506113489190810190612cef565b905092915050565b6000606060026000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611423578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611387565b505050509050600080905060008090505b82518110156114765761146783828151811061144c57fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611434565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b60008060008085905060006021808751816114b057fe5b0402905060008111156114c9576114c687611852565b91505b6000602190505b818111611553576000600182038801519050818801519550806000602081106114f557fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561153a5761153386856112cf565b9350611547565b61154484876112cf565b93505b506021810190506114d0565b508782149450505050509392505050565b6040516115709061367f565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff1610156116565760606115b8868367ffffffffffffffff1660416125ae565b905060006115cf828961263a90919063ffffffff16565b90506115d9612ac9565b6115e38a83611663565b90506115ef8a83611177565b801561162657508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b15611648578194506116458160200151876123f090919063ffffffff16565b95505b50505060418101905061158d565b5081925050509392505050565b61166b612ac9565b606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561173c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906116a0565b50505050905060008090505b81518110156117c4578373ffffffffffffffffffffffffffffffffffffffff1682828151811061177457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156117b7578181815181106117a857fe5b602002602001015192506117c4565b8080600101915050611748565b505092915050565b60006117d6611828565b90506117e28133611177565b6117eb57600080fd5b60001515600160009054906101000a900460ff1615151461180b57600080fd5b60018060006101000a81548160ff02191690831515021790555050565b600061183343611c94565b905090565b600061184b611845611828565b83611177565b9050919050565b60006002600060f81b8360405160200161186d9291906135ea565b6040516020818303038152906040526040516118899190613653565b602060405180830381855afa1580156118a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118c99190810190612cef565b9050919050565b6000806000806118f160016118e3611828565b6123f090919063ffffffff16565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b606080606060016040519080825280602002602001820160405280156119795781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f78160008151811061199e57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606001604051908082528060200260200182016040528015611a0a5781602001602082028038833980820191505090505b509050600a81600081518110611a1c57fe5b60200260200101818152505081819350935050509091565b60ff81565b60036020528160005260406000208181548110611a5257fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000600160009054906101000a900460ff16905090565b6000611ac7611ac1611828565b8361099e565b9050919050565b604051611ada9061366a565b604051809103902081565b6000606060036000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611bb8578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611b1c565b505050509050600080905060008090505b8251811015611c0b57611bfc838281518110611be157fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611bc9565b508092505050919050565b604051611c2290613694565b604051809103902081565b600080600080611c3b611828565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b60005481565b60008060058054905090505b6000811115611d5457611cb1612b00565b6004600060056001850381548110611cc557fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611d2257506000816040015114155b8015611d32575080604001518411155b15611d4557806000015192505050611d8f565b50808060019003915050611ca0565b5060006005805490501115611d8a57600560016005805490500381548110611d7857fe5b90600052602060002001549050611d8f565b600090505b919050565b606080611da0436107c2565b915091509091565b60058181548110611db557fe5b906000526020600020016000915090505481565b6060611ddc611dd78661240f565b61243d565b9050604051611dea9061367f565b6040518091039020611e0f82600081518110611e0257fe5b6020026020010151612744565b8051906020012014611e56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4d90613796565b60405180910390fd5b600260ff16611e7882600181518110611e6b57fe5b602002602001015161251a565b14611eb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eaf90613836565b60405180910390fd5b611f31611ed882600481518110611ecb57fe5b602002602001015161251a565b60001b600285604051611eeb9190613653565b602060405180830381855afa158015611f08573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250611f2b9190810190612cef565b84611499565b611f70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6790613856565b60405180910390fd5b6000611f7a611828565b90506000611f908288805190602001208861157b565b9050611fd46001611fc66003611fb86002611faa88611350565b6127d090919063ffffffff16565b61280a90919063ffffffff16565b6123f090919063ffffffff16565b811015612016576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161200d90613876565b60405180910390fd5b50505050505050565b600281565b6002602052816000526040600020818154811061203d57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006040438161209457fe5b04905090565b60046020528060005260406000206000915090508060000154908060010154908060020154905083565b60406000819055506060806120d7611944565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600460008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506005819080600181540180825580915050906001820390600052602060002001600090919290919091505550600060026000838152602001908152602001600020816121819190612a97565b50600060036000838152602001908152602001600020816121a29190612a97565b5060008090505b83518110156122c6576002600083815260200190815260200160002080548091906001016121d79190612a97565b5060405180606001604052808281526020018483815181106121f557fe5b6020026020010151815260200185838151811061220e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060026000848152602001908152602001600020828154811061224d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506121a9565b5060008090505b83518110156123ea576003600083815260200190815260200160002080548091906001016122fb9190612a97565b50604051806060016040528082815260200184838151811061231957fe5b6020026020010151815260200185838151811061233257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060036000848152602001908152602001600020828154811061237157fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506122cd565b50505050565b60008082840190508381101561240557600080fd5b8091505092915050565b612417612b21565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061244882612830565b61245157600080fd5b600061245c8361287e565b905060608160405190808252806020026020018201604052801561249a57816020015b612487612b3b565b81526020019060019003908161247f5790505b50905060006124ac85602001516128ef565b8560200151019050600080600090505b8481101561250d576124cd83612978565b91506040518060400160405280838152602001848152508482815181106124f057fe5b6020026020010181905250818301925080806001019150506124bc565b5082945050505050919050565b600080826000015111801561253457506021826000015111155b61253d57600080fd5b600061254c83602001516128ef565b9050600081846000015103905060008083866020015101905080519150602083101561257f57826020036101000a820491505b81945050505050919050565b6000601582600001511461259e57600080fd5b6125a78261251a565b9050919050565b6060818301845110156125c057600080fd5b60608215600081146125dd5760405191506020820160405261262e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561261b57805183526020830192506020810190506125fe565b50868552601f19601f8301166040525050505b50809150509392505050565b6000806000806041855114612655576000935050505061273e565b602085015192506040850151915060ff6041860151169050601b8160ff16101561268057601b810190505b601b8160ff16141580156126985750601c8160ff1614155b156126a9576000935050505061273e565b6000600187838686604051600081526020016040526040516126ce9493929190613731565b6020604051602081039080840390855afa1580156126f0573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561273657600080fd5b809450505050505b92915050565b6060600082600001511161275757600080fd5b600061276683602001516128ef565b905060008184600001510390506060816040519080825280601f01601f1916602001820160405280156127a85781602001600182028038833980820191505090505b50905060008160200190506127c4848760200151018285612a30565b81945050505050919050565b6000808314156127e35760009050612804565b60008284029050828482816127f457fe5b04146127ff57600080fd5b809150505b92915050565b600080821161281857600080fd5b600082848161282357fe5b0490508091505092915050565b600080826000015114156128475760009050612879565b60008083602001519050805160001a915060c060ff168260ff16101561287257600092505050612879565b6001925050505b919050565b6000808260000151141561289557600090506128ea565b600080905060006128a984602001516128ef565b84602001510190506000846000015185602001510190505b808210156128e3576128d282612978565b8201915082806001019350506128c1565b8293505050505b919050565b600080825160001a9050608060ff1681101561290f576000915050612973565b60b860ff16811080612934575060c060ff168110158015612933575060f860ff1681105b5b15612943576001915050612973565b60c060ff168110156129635760018060b80360ff16820301915050612973565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156129995760019150612a26565b60b860ff168110156129b6576001608060ff168203019150612a25565b60c060ff168110156129e65760b78103600185019450806020036101000a85510460018201810193505050612a24565b60f860ff16811015612a0357600160c060ff168203019150612a23565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415612a3e57612a92565b5b602060ff168110612a6e5782518252602060ff1683019250602060ff1682019150602060ff1681039050612a3f565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b815481835581811115612ac457600302816003028360005260206000209182019101612ac39190612b55565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b612ba891905b80821115612ba45760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600301612b5b565b5090565b90565b600081359050612bba81613b33565b92915050565b600081359050612bcf81613b4a565b92915050565b600081519050612be481613b4a565b92915050565b60008083601f840112612bfc57600080fd5b8235905067ffffffffffffffff811115612c1557600080fd5b602083019150836001820283011115612c2d57600080fd5b9250929050565b600082601f830112612c4557600080fd5b8135612c58612c5382613982565b613955565b91508082526020830160208301858383011115612c7457600080fd5b612c7f838284613add565b50505092915050565b600081359050612c9781613b61565b92915050565b600060208284031215612caf57600080fd5b6000612cbd84828501612bab565b91505092915050565b600060208284031215612cd857600080fd5b6000612ce684828501612bc0565b91505092915050565b600060208284031215612d0157600080fd5b6000612d0f84828501612bd5565b91505092915050565b60008060408385031215612d2b57600080fd5b6000612d3985828601612bc0565b9250506020612d4a85828601612bc0565b9150509250929050565b600080600060608486031215612d6957600080fd5b6000612d7786828701612bc0565b9350506020612d8886828701612bc0565b925050604084013567ffffffffffffffff811115612da557600080fd5b612db186828701612c34565b9150509250925092565b60008060008060808587031215612dd157600080fd5b600085013567ffffffffffffffff811115612deb57600080fd5b612df787828801612c34565b945050602085013567ffffffffffffffff811115612e1457600080fd5b612e2087828801612c34565b935050604085013567ffffffffffffffff811115612e3d57600080fd5b612e4987828801612c34565b925050606085013567ffffffffffffffff811115612e6657600080fd5b612e7287828801612c34565b91505092959194509250565b600060208284031215612e9057600080fd5b6000612e9e84828501612c88565b91505092915050565b60008060408385031215612eba57600080fd5b6000612ec885828601612c88565b9250506020612ed985828601612bab565b9150509250929050565b600080600060608486031215612ef857600080fd5b6000612f0686828701612c88565b9350506020612f1786828701612bc0565b925050604084013567ffffffffffffffff811115612f3457600080fd5b612f4086828701612c34565b9150509250925092565b60008060408385031215612f5d57600080fd5b6000612f6b85828601612c88565b9250506020612f7c85828601612c88565b9150509250929050565b600080600080600080600060a0888a031215612fa157600080fd5b6000612faf8a828b01612c88565b9750506020612fc08a828b01612c88565b9650506040612fd18a828b01612c88565b955050606088013567ffffffffffffffff811115612fee57600080fd5b612ffa8a828b01612bea565b9450945050608088013567ffffffffffffffff81111561301957600080fd5b6130258a828b01612bea565b925092505092959891949750929550565b60006130428383613066565b60208301905092915050565b600061305a83836135bd565b60208301905092915050565b61306f81613a52565b82525050565b61307e81613a52565b82525050565b600061308f826139ce565b6130998185613a09565b93506130a4836139ae565b8060005b838110156130d55781516130bc8882613036565b97506130c7836139ef565b9250506001810190506130a8565b5085935050505092915050565b60006130ed826139d9565b6130f78185613a1a565b9350613102836139be565b8060005b8381101561313357815161311a888261304e565b9750613125836139fc565b925050600181019050613106565b5085935050505092915050565b61314981613a64565b82525050565b61316061315b82613a70565b613b1f565b82525050565b61316f81613a9c565b82525050565b61318661318182613a9c565b613b29565b82525050565b6000613197826139e4565b6131a18185613a2b565b93506131b1818560208601613aec565b80840191505092915050565b60006131ca600483613a47565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b600061320a602d83613a36565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000613270600f83613a47565b91507f6865696d64616c6c2d50357258776700000000000000000000000000000000006000830152600f82019050919050565b60006132b0601383613a36565b91507f436861696e20494420697320696e76616c6964000000000000000000000000006000830152602082019050919050565b60006132f0600f83613a36565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000613330601383613a36565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000613370604583613a36565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b60006133fc602a83613a36565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613462601483613a36565b91507f566f7465207479706520697320696e76616c69640000000000000000000000006000830152602082019050919050565b60006134a2601683613a36565b91507f5472616e73616374696f6e20697320696e76616c6964000000000000000000006000830152602082019050919050565b60006134e2600583613a47565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613522602483613a36565b91507f4e6f7420656e6f7567687420706f77657220746f206368616e6765207468652060008301527f7370616e000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60608201600082015161359160008501826135bd565b5060208201516135a460208501826135bd565b5060408201516135b76040850182613066565b50505050565b6135c681613ac6565b82525050565b6135d581613ac6565b82525050565b6135e481613ad0565b82525050565b60006135f6828561314f565b6001820191506136068284613175565b6020820191508190509392505050565b6000613622828661314f565b6001820191506136328285613175565b6020820191506136428284613175565b602082019150819050949350505050565b600061365f828461318c565b915081905092915050565b6000613675826131bd565b9150819050919050565b600061368a82613263565b9150819050919050565b600061369f826134d5565b9150819050919050565b60006020820190506136be6000830184613075565b92915050565b600060408201905081810360008301526136de8185613084565b905081810360208301526136f281846130e2565b90509392505050565b60006020820190506137106000830184613140565b92915050565b600060208201905061372b6000830184613166565b92915050565b60006080820190506137466000830187613166565b61375360208301866135db565b6137606040830185613166565b61376d6060830184613166565b95945050505050565b6000602082019050818103600083015261378f816131fd565b9050919050565b600060208201905081810360008301526137af816132a3565b9050919050565b600060208201905081810360008301526137cf816132e3565b9050919050565b600060208201905081810360008301526137ef81613323565b9050919050565b6000602082019050818103600083015261380f81613363565b9050919050565b6000602082019050818103600083015261382f816133ef565b9050919050565b6000602082019050818103600083015261384f81613455565b9050919050565b6000602082019050818103600083015261386f81613495565b9050919050565b6000602082019050818103600083015261388f81613515565b9050919050565b60006060820190506138ab600083018461357b565b92915050565b60006020820190506138c660008301846135cc565b92915050565b60006060820190506138e160008301866135cc565b6138ee60208301856135cc565b6138fb6040830184613075565b949350505050565b600060608201905061391860008301866135cc565b61392560208301856135cc565b61393260408301846135cc565b949350505050565b600060208201905061394f60008301846135db565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561397857600080fd5b8060405250919050565b600067ffffffffffffffff82111561399957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000613a5d82613aa6565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b83811015613b0a578082015181840152602081019050613aef565b83811115613b19576000848401525b50505050565b6000819050919050565b6000819050919050565b613b3c81613a52565b8114613b4757600080fd5b50565b613b5381613a9c565b8114613b5e57600080fd5b50565b613b6a81613ac6565b8114613b7557600080fd5b5056fea365627a7a7231582041043c020490417f03b23833da19152e2e105982aaa0228db2459085c981a3f16c6578706572696d656e74616cf564736f6c63430005100040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fce28085b549b31600000", + "code": "0x" + }, + "71562b71999873DB5b286dF957af199Ec94617F7": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/consensus/bor_test/span.json b/consensus/bor_test/span.json new file mode 100644 index 0000000000..f4be94eeb8 --- /dev/null +++ b/consensus/bor_test/span.json @@ -0,0 +1,95 @@ +{ + "height": "42841", + "result": { + "span_id": 1, + "start_block": 256, + "end_block": 6655, + "validator_set": { + "validators": [{ + "ID": 3, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1", + "signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c", + "last_updated": 0, + "accum": -40000 + }, { + "ID": 4, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x04d9d09f2afc9da3cccc164e8112eb6911a63f5ede10169768f800df83cf99c73f944411e9d4fac3543b11c5f84a82e56b36cfcd34f1d065855c1e2b27af8b5247", + "signer": "0x461295d3d9249215e758e939a150ab180950720b", + "last_updated": 0, + "accum": 10000 + }, { + "ID": 5, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932", + "signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0", + "last_updated": 0, + "accum": 10000 + }, { + "ID": 1, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead", + "signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3", + "last_updated": 0, + "accum": 10000 + }, { + "ID": 2, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232", + "signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220", + "last_updated": 0, + "accum": 10000 + }], + "proposer": { + "ID": 3, + "startEpoch": 0, + "endEpoch": 0, + "power": 10000, + "pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1", + "signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220", + "last_updated": 0, + "accum": -40000 + } + }, + "selected_producers": [{ + "ID": 5, + "startEpoch": 0, + "endEpoch": 0, + "power": 1, + "pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932", + "signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0", + "last_updated": 0, + "accum": 10000 + }, { + "ID": 1, + "startEpoch": 0, + "endEpoch": 0, + "power": 1, + "pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead", + "signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3", + "last_updated": 0, + "accum": 10000 + }, { + "ID": 2, + "startEpoch": 0, + "endEpoch": 0, + "power": 2, + "pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232", + "signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c", + "last_updated": 0, + "accum": 5000 + }], + "bor_chain_id": "15001" + } +} diff --git a/core/tx_pool.go b/core/tx_pool.go index a089394a18..02011586c3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -27,6 +27,7 @@ import ( "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/common/prque" + "github.com/maticnetwork/bor/consensus" "github.com/maticnetwork/bor/core/state" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/event" @@ -116,14 +117,22 @@ const ( TxStatusIncluded ) +// bor acts as a way to be able to type cast consensus.Engine; +// since importing "github.com/maticnetwork/bor/consensus/bor" results in a cyclic dependency +type bor interface { + IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool +} + // blockChain provides the state of blockchain and current gas limit to do // some pre checks in tx pool and event subscribers. type blockChain interface { CurrentBlock() *types.Block GetBlock(hash common.Hash, number uint64) *types.Block StateAt(root common.Hash) (*state.StateDB, error) - SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription + + Engine() consensus.Engine + CurrentHeader() *types.Header } // TxPoolConfig are the configuration parameters of the transaction pool. @@ -527,7 +536,9 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network - if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { + if !local && + !pool.chain.Engine().(bor).IsValidatorAction(pool.chain.(consensus.ChainReader), from, tx) && + pool.gasPrice.Cmp(tx.GasPrice()) > 0 { return ErrUnderpriced } // Ensure the transaction adheres to nonce ordering diff --git a/go.mod b/go.mod index b305c65352..b9b765a52c 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,8 @@ require ( github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect - github.com/stretchr/testify v1.2.2 + github.com/stretchr/objx v0.2.0 // indirect + github.com/stretchr/testify v1.3.0 github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 diff --git a/go.sum b/go.sum index 4c4267f25f..c946c411bc 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,7 @@ github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnC github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= @@ -131,8 +132,13 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1 github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= diff --git a/mocks/IHeimdallClient.go b/mocks/IHeimdallClient.go new file mode 100644 index 0000000000..cb09800c74 --- /dev/null +++ b/mocks/IHeimdallClient.go @@ -0,0 +1,71 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import ( + bor "github.com/maticnetwork/bor/consensus/bor" + mock "github.com/stretchr/testify/mock" +) + +// IHeimdallClient is an autogenerated mock type for the IHeimdallClient type +type IHeimdallClient struct { + mock.Mock +} + +// Fetch provides a mock function with given fields: paths +func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, error) { + _va := make([]interface{}, len(paths)) + for _i := range paths { + _va[_i] = paths[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *bor.ResponseWithHeight + if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok { + r0 = rf(paths...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*bor.ResponseWithHeight) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(...string) error); ok { + r1 = rf(paths...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FetchWithRetry provides a mock function with given fields: paths +func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHeight, error) { + _va := make([]interface{}, len(paths)) + for _i := range paths { + _va[_i] = paths[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *bor.ResponseWithHeight + if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok { + r0 = rf(paths...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*bor.ResponseWithHeight) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(...string) error); ok { + r1 = rf(paths...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +}