Skip to content

Commit

Permalink
Merge pull request ethereum#24 from maticnetwork/dev-test-commit-span
Browse files Browse the repository at this point in the history
MAT-869: Allow commitSpan/State actions if they are underpriced + Test commit span
  • Loading branch information
atvanguard authored Mar 18, 2020
2 parents e189cb8 + bd95198 commit c69ad13
Show file tree
Hide file tree
Showing 11 changed files with 611 additions and 66 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ jobs:
- checkout # check out source code to working directory
- run:
command: make bor
- run:
command: make test
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 72 additions & 26 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"io"
"math"
"math/big"
"net/http"

"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
//
Expand Down
83 changes: 48 additions & 35 deletions consensus/bor/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,69 +19,82 @@ type ResponseWithHeight struct {
Result json.RawMessage `json:"result"`
}

// internal fetch method
func internalFetch(client http.Client, u *url.URL) (*ResponseWithHeight, error) {
res, err := client.Get(u.String())
if err != nil {
return nil, err
}
defer res.Body.Close()
type IHeimdallClient interface {
Fetch(paths ...string) (*ResponseWithHeight, error)
FetchWithRetry(paths ...string) (*ResponseWithHeight, error)
}

// check status code
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error while fetching data from Heimdall")
}
type HeimdallClient struct {
u *url.URL
client http.Client
}

// get response
body, err := ioutil.ReadAll(res.Body)
func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
u, err := url.Parse(urlString)
if err != nil {
return nil, err
}

// unmarshall data from buffer
var response ResponseWithHeight
if err := json.Unmarshal(body, &response); err != nil {
return nil, err
h := &HeimdallClient{
u: u,
client: http.Client{
Timeout: time.Duration(5 * time.Second),
},
}

return &response, nil
return h, 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
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 != "" {
u.Path = path.Join(u.Path, e)
h.u.Path = path.Join(h.u.Path, e)
}
}

for {
res, err := internalFetch(client, u)
res, err := h.internalFetch()
if err == nil && res != nil {
return res, nil
}
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", u.Path)
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", h.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)
// internal fetch method
func (h *HeimdallClient) internalFetch() (*ResponseWithHeight, error) {
res, err := h.client.Get(h.u.String())
if err != nil {
return nil, err
}
defer res.Body.Close()

for _, e := range paths {
if e != "" {
u.Path = path.Join(u.Path, e)
}
// check status code
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error while fetching data from Heimdall")
}

// get response
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}

// unmarshall data from buffer
var response ResponseWithHeight
if err := json.Unmarshal(body, &response); err != nil {
return nil, err
}

return internalFetch(client, u)
return &response, nil
}
Loading

0 comments on commit c69ad13

Please sign in to comment.