-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Nico Vergauwen
authored and
Nico Vergauwen
committed
Oct 23, 2019
1 parent
2675094
commit fc6c9fb
Showing
6 changed files
with
194 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package eth | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math/big" | ||
"strings" | ||
|
||
ethereum "github.com/ethereum/go-ethereum" | ||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
ethabi "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.ChainReader | ||
ethereum.ChainStateReader | ||
ethereum.ChainSyncReader | ||
ethereum.TransactionReader | ||
ethereum.TransactionSender | ||
ethereum.ContractCaller | ||
ethereum.PendingContractCaller | ||
ethereum.PendingStateReader | ||
// ethereum.PendingStateEventer | ||
ethereum.GasEstimator | ||
ethereum.GasPricer | ||
ethereum.LogFilterer | ||
|
||
NetworkID(ctx context.Context) (*big.Int, error) | ||
} | ||
|
||
type backend struct { | ||
*ethclient.Client | ||
methods map[string]*method | ||
nonceManager *NonceManager | ||
} | ||
|
||
type method struct { | ||
name string | ||
abi *abi.ABI | ||
} | ||
|
||
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) { | ||
var nonce uint64 | ||
var err error | ||
if b.nonceManager != nil { | ||
b.nonceManager.Lock(account) | ||
defer func() { | ||
if err == nil { | ||
b.nonceManager.Update(account, nonce) | ||
} | ||
|
||
b.nonceManager.Unlock(account) | ||
}() | ||
|
||
nonce, err = b.nonceManager.Next(account) | ||
if err != nil { | ||
return 0, err | ||
} | ||
} else { | ||
nonce, err = b.Client.PendingNonceAt(ctx, account) | ||
if err != nil { | ||
return 0, fmt.Errorf("failed to retrieve account nonce: %v", err) | ||
} | ||
} | ||
|
||
return nonce, nil | ||
} | ||
|
||
func (b *backend) SendTransaction(ctx context.Context, tx *types.Transaction) error { | ||
err := b.Client.SendTransaction(ctx, tx) | ||
|
||
// decode tx data | ||
data := tx.Data() | ||
method := b.methods[string(data[:4])] | ||
params := make(map[string]interface{}) | ||
method.abi.UnpackIntoMap(params, method.name, data[4:]) | ||
paramsString := formatParams((params)) | ||
|
||
if err != nil { | ||
glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\". Params: %v \nTransaction Failed: %v\n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method.name, paramsString, err, strings.Repeat("*", 75)) | ||
return err | ||
} | ||
|
||
glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\". Hash: \"%v\". Params: %v \n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method.name, tx.Hash().String(), paramsString, 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]*method, error) { | ||
methods := make(map[string]*method) | ||
for _, ABI := range abis { | ||
abi, err := ethabi.JSON(strings.NewReader(ABI)) | ||
if err != nil { | ||
return map[string]*method{}, err | ||
} | ||
for _, m := range abi.Methods { | ||
methods[string(m.ID())] = &method{ | ||
name: m.Name, | ||
abi: &abi, | ||
} | ||
} | ||
} | ||
|
||
return methods, nil | ||
} | ||
|
||
func formatParams(params map[string]interface{}) string { | ||
var ps string | ||
for k, v := range params { | ||
ps += fmt.Sprintf("\t %v: %v", k, v) | ||
} | ||
ps += "\t" | ||
return ps | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.