Skip to content

Commit

Permalink
Merge pull request #1125 from livepeer/nv/nonce-gap
Browse files Browse the repository at this point in the history
gomod, eth: fix nonce gap issues
  • Loading branch information
kyriediculous authored Oct 25, 2019
2 parents 1f604fd + 4f2e591 commit 053db68
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 84 deletions.
8 changes: 4 additions & 4 deletions cmd/livepeer_cli/livepeer_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ func (w *wizard) doCLIOpt(choice string, options []wizardOpt) {
log.Error("That's not something I can do")
}

var RinkebyNetworkId = "4"
var DevenvNetworkId = "54321"
var RinkebyChainID = "4"
var DevenvChainID = "54321"

func (w *wizard) checkNet() {
nID := httpGet(fmt.Sprintf("http://%v:%v/EthNetworkID", w.host, w.httpPort))
w.testnet = nID == RinkebyNetworkId || nID == DevenvNetworkId
nID := httpGet(fmt.Sprintf("http://%v:%v/EthChainID", w.host, w.httpPort))
w.testnet = nID == RinkebyChainID || nID == DevenvChainID
w.offchain = nID == "offchain"
}
141 changes: 141 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package eth

import (
"context"
"math/big"
"strings"

ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/golang/glog"
"github.com/livepeer/go-livepeer/eth/contracts"
)

var abis = []string{
contracts.BondingManagerABI,
contracts.ControllerABI,
contracts.LivepeerTokenABI,
contracts.LivepeerTokenFaucetABI,
contracts.MinterABI,
contracts.RoundsManagerABI,
contracts.ServiceRegistryABI,
contracts.TicketBrokerABI,
}

type Backend interface {
ethereum.ChainStateReader
ethereum.TransactionReader
ethereum.TransactionSender
ethereum.ContractCaller
ethereum.PendingContractCaller
ethereum.PendingStateReader
ethereum.GasEstimator
ethereum.GasPricer
ethereum.LogFilterer

ChainID(ctx context.Context) (*big.Int, error)
}

type backend struct {
*ethclient.Client
methods map[string]string
nonceManager *NonceManager
}

func NewBackend(client *ethclient.Client) (Backend, error) {
methods, err := makeMethodsMap()
if err != nil {
return nil, err
}

return &backend{
client,
methods,
NewNonceManager(client),
}, nil
}

func (b *backend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
b.nonceManager.Lock(account)
defer b.nonceManager.Unlock(account)

return b.nonceManager.Next(account)
}

func (b *backend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
err := b.Client.SendTransaction(ctx, tx)
if err != nil {
return err
}

// update local nonce
msg, err := tx.AsMessage(types.HomesteadSigner{})
if err != nil {
return err
}
sender := msg.From()
b.nonceManager.Lock(sender)
b.nonceManager.Update(sender, tx.Nonce())
b.nonceManager.Unlock(sender)

data := tx.Data()
method, ok := b.methods[string(data[:4])]
if !ok {
method = "unknown"
}

if err != nil {
glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\". \nTransaction Failed: %v\n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method, err, strings.Repeat("*", 75))
return err
}

glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\". Hash: \"%v\". \n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method, tx.Hash().String(), strings.Repeat("*", 75))

return nil
}

func (b *backend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
return b.retryRemoteCall(func() ([]byte, error) {
return b.Client.CallContract(ctx, msg, blockNumber)
})
}

func (b *backend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
return b.retryRemoteCall(func() ([]byte, error) {
return b.Client.PendingCallContract(ctx, msg)
})
}

func (b *backend) retryRemoteCall(remoteCall func() ([]byte, error)) (out []byte, err error) {
count := 3 // consider making this a package-level global constant
retry := true // consider making this a package-level global constant

for i := 0; i < count && retry; i++ {
out, err = remoteCall()
if err != nil && (err.Error() == "EOF" || err.Error() == "tls: use of closed connection") {
glog.V(4).Infof("Retrying call to remote ethereum node")
} else {
retry = false
}
}

return out, err
}

func makeMethodsMap() (map[string]string, error) {
methods := make(map[string]string)
for _, ABI := range abis {
parsedAbi, err := abi.JSON(strings.NewReader(ABI))
if err != nil {
return map[string]string{}, err
}
for _, m := range parsedAbi.Methods {
methods[string(m.ID())] = m.Name
}
}

return methods, nil
}
15 changes: 9 additions & 6 deletions eth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var (
type LivepeerEthClient interface {
Setup(password string, gasLimit uint64, gasPrice *big.Int) error
Account() accounts.Account
Backend() (*ethclient.Client, error)
Backend() (Backend, error)

// Rounds
InitializeRound() (*types.Transaction, error)
Expand Down Expand Up @@ -117,7 +117,7 @@ type LivepeerEthClient interface {

type client struct {
accountManager AccountManager
backend *ethclient.Client
backend Backend

controllerAddr ethcommon.Address
tokenAddr ethcommon.Address
Expand Down Expand Up @@ -145,12 +145,17 @@ type client struct {
txTimeout time.Duration
}

func NewClient(accountAddr ethcommon.Address, keystoreDir string, backend *ethclient.Client, controllerAddr ethcommon.Address, txTimeout time.Duration) (LivepeerEthClient, error) {
func NewClient(accountAddr ethcommon.Address, keystoreDir string, eth *ethclient.Client, controllerAddr ethcommon.Address, txTimeout time.Duration) (LivepeerEthClient, error) {
am, err := NewAccountManager(accountAddr, keystoreDir)
if err != nil {
return nil, err
}

backend, err := NewBackend(eth)
if err != nil {
return nil, err
}

return &client{
accountManager: am,
backend: backend,
Expand All @@ -174,8 +179,6 @@ func (c *client) SetGasInfo(gasLimit uint64, gasPrice *big.Int) error {
return err
}

opts.NonceManager = NewNonceManager(c.backend)

if err := c.setContracts(opts); err != nil {
return err
} else {
Expand Down Expand Up @@ -357,7 +360,7 @@ func (c *client) Account() accounts.Account {
return c.accountManager.Account()
}

func (c *client) Backend() (*ethclient.Client, error) {
func (c *client) Backend() (Backend, error) {
if c.backend == nil {
return nil, ErrMissingBackend
} else {
Expand Down
3 changes: 1 addition & 2 deletions eth/stubclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/ethereum/go-ethereum/common"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
lpTypes "github.com/livepeer/go-livepeer/eth/types"
"github.com/livepeer/go-livepeer/pm"
"github.com/stretchr/testify/mock"
Expand Down Expand Up @@ -179,7 +178,7 @@ type stubTranscoder struct {

func (e *StubClient) Setup(password string, gasLimit uint64, gasPrice *big.Int) error { return nil }
func (e *StubClient) Account() accounts.Account { return accounts.Account{Address: e.TranscoderAddress} }
func (e *StubClient) Backend() (*ethclient.Client, error) { return nil, ErrMissingBackend }
func (e *StubClient) Backend() (Backend, error) { return nil, ErrMissingBackend }

// Rounds

Expand Down
2 changes: 1 addition & 1 deletion eth/watchers/eventdecoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewEventDecoder(addr ethcommon.Address, abiJSON string) (*EventDecoder, err

topicToEventName := make(map[ethcommon.Hash]string)
for _, event := range abi.Events {
topicToEventName[event.Id()] = event.Name
topicToEventName[event.ID()] = event.Name
}

return &EventDecoder{
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ require (
github.com/fatih/color v1.7.0 // indirect
// replace example.com/some/dependency => example.com/some/dependency-fork v1.2.3
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
// github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190403181518-312b5175032f // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
// github.com/gballet/go-libpcsclite v0.0.0-20190403181518-312b5175032f // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.3.2
github.com/gorilla/websocket v1.4.1 // indirect
github.com/graph-gophers/graphql-go v0.0.0-20190917030536-38a077bc812d // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/howeyc/fsnotify v0.9.0 // indirect
github.com/huin/goupnp v1.0.0 // indirect
github.com/influxdata/influxdb v1.7.8 // indirect
github.com/jackpal/go-nat-pmp v1.0.1 // indirect
github.com/karalabe/hid v1.0.0 // indirect
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/livepeer/lpms v0.0.0-20191004153601-83352b59757e
github.com/livepeer/m3u8 v0.11.0
Expand Down Expand Up @@ -65,6 +67,4 @@ require (
gopkg.in/urfave/cli.v1 v1.0.0-00010101000000-000000000000 // indirect
)

replace github.com/ethereum/go-ethereum => github.com/livepeer/go-ethereum v1.8.4-0.20190523183241-7e95cbcfcd82

replace gopkg.in/urfave/cli.v1 => github.com/urfave/cli v1.22.2-0.20191002033821-63cd2e3d6bb5
Loading

0 comments on commit 053db68

Please sign in to comment.