diff --git a/client/asset/eth/eth.go b/client/asset/eth/eth.go index 8de5e626fd..ec18447685 100644 --- a/client/asset/eth/eth.go +++ b/client/asset/eth/eth.go @@ -803,6 +803,8 @@ func (eth *ExchangeWallet) checkForNewBlocks() { go eth.tipChange(nil) } +// Balance is the current balance, including information about the pending +// balance. type Balance struct { Current, Pending, PendingIn, PendingOut *big.Int } diff --git a/client/asset/eth/eth_test.go b/client/asset/eth/eth_test.go index d59e438df5..36f4c2b177 100644 --- a/client/asset/eth/eth_test.go +++ b/client/asset/eth/eth_test.go @@ -53,8 +53,6 @@ type testNode struct { syncProg ethereum.SyncProgress bal *Balance balErr error - pendingTxs []*types.Transaction - pendingTxsErr error initGas uint64 initGasErr error signDataErr error diff --git a/client/asset/eth/nodeclient.go b/client/asset/eth/nodeclient.go index fa73b42d94..d62be5415c 100644 --- a/client/asset/eth/nodeclient.go +++ b/client/asset/eth/nodeclient.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "math/big" + "sync" "decred.org/dcrdex/client/asset" "decred.org/dcrdex/dex" @@ -45,15 +46,16 @@ var ( // nodeClient satisfies the ethFetcher interface. Do not use until Connect is // called. type nodeClient struct { - net dex.Network - log dex.Logger - creds *accountCredentials - p2pSrv *p2p.Server - ec *ethclient.Client - node *node.Node - leth *les.LightEthereum - chainID *big.Int - contractors map[uint32]contractor + net dex.Network + log dex.Logger + creds *accountCredentials + p2pSrv *p2p.Server + ec *ethclient.Client + node *node.Node + leth *les.LightEthereum + chainID *big.Int + contractors map[uint32]contractor + nonceSendMtx sync.Mutex } func newNodeClient(dir string, net dex.Network, log dex.Logger) (*nodeClient, error) { @@ -184,10 +186,10 @@ func (n *nodeClient) balanceAt(ctx context.Context, addr common.Address, bn rpc. } func (n *nodeClient) addressBalance(ctx context.Context, addr common.Address) (*big.Int, error) { - return n.balanceAt(ctx, n.creds.addr, rpc.LatestBlockNumber) + return n.balanceAt(ctx, addr, rpc.LatestBlockNumber) } -// balance gets the current balance of an address. +// balance gets the current and pending balances. func (n *nodeClient) balance(ctx context.Context) (*Balance, error) { pendingBal, err := n.balanceAt(ctx, n.creds.addr, rpc.PendingBlockNumber) if err != nil { @@ -211,6 +213,8 @@ func (n *nodeClient) balance(ctx context.Context) (*Balance, error) { outgoing.Add(outgoing, tx.Value()) } + // pending = current + incoming - outgoing + // => incoming = pending + outgoing - current incoming := pendingBal.Add(pendingBal, outgoing) incoming.Sub(incoming, bal) @@ -302,6 +306,9 @@ func (n *nodeClient) listWallets(ctx context.Context) []accounts.Wallet { func (n *nodeClient) sendTransaction(ctx context.Context, txOpts *bind.TransactOpts, to common.Address, data []byte) (*types.Transaction, error) { + n.nonceSendMtx.Lock() + defer n.nonceSendMtx.Unlock() + nonce, err := n.leth.ApiBackend.GetPoolNonce(ctx, n.creds.addr) if err != nil { return nil, fmt.Errorf("error getting nonce: %v", err) diff --git a/client/asset/eth/nodeclient_harness_test.go b/client/asset/eth/nodeclient_harness_test.go index a195743d95..201fba6ddd 100644 --- a/client/asset/eth/nodeclient_harness_test.go +++ b/client/asset/eth/nodeclient_harness_test.go @@ -395,6 +395,16 @@ func testSendTransaction(t *testing.T) { if err != nil { t.Fatal(err) } + + bal, _ := ethClient.balance(ctx) + if bal.PendingIn.Cmp(dexeth.GweiToWei(1)) != 0 { // We sent it to ourselves. + t.Fatalf("pending in not showing") + } + + if bal.PendingOut.Cmp(dexeth.GweiToWei(1)) != 0 { + t.Fatalf("pending out not showing") + } + spew.Dump(tx) if err := waitForMined(t, time.Second*10, false); err != nil { t.Fatal(err)