diff --git a/README.md b/README.md index 778be8f..45d6c3e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Sends an amount of Nano from one account to another. The source account (supplie gonano receive -w0 -Receives all pending amounts for wallet #0. To receive pending amounts for a single account, +Receives all receivable amounts for wallet #0. To receive receivable amounts for a single account, gonano receive -a @@ -62,7 +62,7 @@ Main entrypoint to the package. The first function creates a wallet using a trad func (w *Wallet) ScanForAccounts() (err error) -Scans the wallet for non-empty accounts, including not yet opened accounts with pending amounts. +Scans the wallet for non-empty accounts, including not yet opened accounts with receivable amounts. func (w *Wallet) NewAccount(index *uint32) (a *Account, err error) @@ -73,9 +73,9 @@ Creates a new account within the wallet. If `index` is non-`nil`, derives the ac Gets the account with the given `address`, or all the accounts known to the wallet. - func (w *Wallet) ReceivePendings() (err error) + func (w *Wallet) ReceiveReceivables() (err error) -Receives all pending amounts to the wallet. +Receives all receivable amounts to the wallet. func (a *Account) Address() string @@ -85,17 +85,17 @@ Get the address of the account. Get the derivation index of the account. - func (a *Account) Balance() (balance, pending *big.Int, err error) + func (a *Account) Balance() (balance, receivable *big.Int, err error) -Get the owned balance and pending balance of the account. Amounts are in raws. +Get the owned balance and receivable balance of the account. Amounts are in raws. func (a *Account) Send(account string, amount *big.Int) (hash rpc.BlockHash, err error) Send `amount` Nano from this to another `account`. The block hash is returned. - func (a *Account) ReceivePendings() (err error) + func (a *Account) ReceiveReceivables() (err error) -Receives all pending amounts to the account. +Receives all receivable amounts to the account. func (a *Account) ChangeRep(representative string) (hash rpc.BlockHash, err error) @@ -114,7 +114,7 @@ Create an RPC client with URL. Not all RPCs are supported. The following methods are available: - func (c *Client) AccountBalance(account string) (balance, pending *RawAmount, err error) + func (c *Client) AccountBalance(account string) (balance, receivable *RawAmount, err error) func (c *Client) AccountBlockCount(account string) (blockCount uint64, err error) func (c *Client) AccountHistory(account string, count int64, head BlockHash) (history []AccountHistory, previous BlockHash, err error) func (c *Client) AccountHistoryRaw(account string, count int64, head BlockHash) (history []AccountHistoryRaw, previous BlockHash, err error) @@ -123,7 +123,7 @@ Not all RPCs are supported. The following methods are available: func (c *Client) AccountWeight(account string) (weight *RawAmount, err error) func (c *Client) AccountsBalances(accounts []string) (balances map[string]*AccountBalance, err error) func (c *Client) AccountsFrontiers(accounts []string) (frontiers map[string]BlockHash, err error) - func (c *Client) AccountsPending(accounts []string, count int64) (pending map[string]HashToPendingMap, err error) + func (c *Client) AccountsReceivable(accounts []string, count int64) (receivable map[string]HashToReceivableMap, err error) func (c *Client) AvailableSupply() (available *RawAmount, err error) func (c *Client) BlockAccount(hash BlockHash) (account string, err error) func (c *Client) BlockConfirm(hash BlockHash) (started bool, err error) diff --git a/cmd/list.go b/cmd/list.go index 93e63a4..9db9a8e 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -38,35 +38,35 @@ var listCmd = &cobra.Command{ accounts = append(accounts, address) } sort.Strings(accounts) - var balanceSum, pendingSum big.Int + var balanceSum, receivableSum big.Int for _, address := range accounts { - balance, pending := getBalanceAndPrint(address) + balance, receivable := getBalanceAndPrint(address) balanceSum.Add(&balanceSum, &balance.Int) - pendingSum.Add(&pendingSum, &pending.Int) + receivableSum.Add(&receivableSum, &receivable.Int) } if len(accounts) > 1 { fmt.Print(strings.Repeat(" ", 61), "Sum:") - printAmounts(&balanceSum, &pendingSum) + printAmounts(&balanceSum, &receivableSum) } } }, } -func getBalanceAndPrint(account string) (balance, pending *rpc.RawAmount) { +func getBalanceAndPrint(account string) (balance, receivable *rpc.RawAmount) { rpcClient := rpc.Client{URL: rpcURL} - balance, pending, err := rpcClient.AccountBalance(account) + balance, receivable, err := rpcClient.AccountBalance(account) fatalIf(err) fmt.Print(account) - printAmounts(&balance.Int, &pending.Int) - return balance, pending + printAmounts(&balance.Int, &receivable.Int) + return balance, receivable } -func printAmounts(balance, pending *big.Int) { +func printAmounts(balance, receivable *big.Int) { if balance.Sign() > 0 { fmt.Printf(" %s", util.NanoAmount{Raw: balance}) } - if pending.Sign() > 0 { - fmt.Printf(" (+ %s pending)", util.NanoAmount{Raw: pending}) + if receivable.Sign() > 0 { + fmt.Printf(" (+ %s receivable)", util.NanoAmount{Raw: receivable}) } fmt.Println() } diff --git a/cmd/receive.go b/cmd/receive.go index aed9315..281475d 100644 --- a/cmd/receive.go +++ b/cmd/receive.go @@ -6,7 +6,7 @@ import ( var receiveCmd = &cobra.Command{ Use: "receive", - Short: "Receive all pending amounts for a wallet or account", + Short: "Receive all receivable amounts for a wallet or account", Run: func(cmd *cobra.Command, args []string) { if walletAccount == "" { checkWalletIndex() @@ -16,10 +16,10 @@ var receiveCmd = &cobra.Command{ _, err := wi.w.NewAccount(&index) fatalIf(err) } - err := wi.w.ReceivePendings() + err := wi.w.ReceiveReceivables() fatalIf(err) } else { - err := getAccount().ReceivePendings() + err := getAccount().ReceiveReceivables() fatalIf(err) } }, diff --git a/cmd/root.go b/cmd/root.go index 3839b40..6042b9a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -43,9 +43,9 @@ func init() { rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.gonano.yaml)") rootCmd.PersistentFlags().IntVarP(&walletIndex, "wallet", "w", -1, "Index of the wallet to use") rootCmd.PersistentFlags().StringVarP(&walletAccount, "account", "a", "", "Account to operate on") - rootCmd.PersistentFlags().StringVarP(&rpcURL, "rpc", "r", "https://mynano.ninja/api/node", "RPC endpoint URL") + rootCmd.PersistentFlags().StringVarP(&rpcURL, "rpc", "r", "https://app.natrium.io/api", "RPC endpoint URL") rootCmd.PersistentFlags().StringVarP(&rpcWorkURL, "rpc-work", "s", "http://[::1]:7076", "RPC endpoint URL for work generation") - rootCmd.PersistentFlags().IntVarP(&walletAccountIndex, "account-index", "i", -1, "Index of the account within the wallet to use. Not all operations support it yet") + rootCmd.PersistentFlags().IntVarP(&walletAccountIndex, "account-index", "i", -1, "Index of the account within the wallet to use. Not all operations support it yet") } // initConfig reads in config file and ENV variables if set. diff --git a/rpc/account.go b/rpc/account.go index 76b6ef4..51f8ef7 100644 --- a/rpc/account.go +++ b/rpc/account.go @@ -6,14 +6,14 @@ import ( ) // AccountBalance returns how many RAW is owned and how many have not yet been received by account. -func (c *Client) AccountBalance(account string) (balance, pending *RawAmount, err error) { +func (c *Client) AccountBalance(account string) (balance, receivable *RawAmount, err error) { resp, err := c.send(map[string]interface{}{"action": "account_balance", "account": account}) if err != nil { return } - var v struct{ Balance, Pending *RawAmount } + var v struct{ Balance, Receivable *RawAmount } err = json.Unmarshal(resp, &v) - return v.Balance, v.Pending, err + return v.Balance, v.Receivable, err } // AccountBlockCount gets the number of blocks for a specific account. @@ -75,7 +75,7 @@ func (c *Client) AccountInfo(account string) (info AccountInfo, err error) { "account": account, "representative": true, "weight": true, - "pending": true, + "receivable": true, }) if err != nil { return @@ -108,7 +108,7 @@ func (c *Client) AccountWeight(account string) (weight *RawAmount, err error) { // AccountBalance returns how many RAW is owned and how many have not yet been received. type AccountBalance struct { - Balance, Pending *RawAmount + Balance, Receivable *RawAmount } // AccountsBalances returns how many RAW is owned and how many have not yet been received by accounts list. @@ -137,31 +137,31 @@ func (c *Client) AccountsFrontiers(accounts []string) (frontiers map[string]Bloc return v.Frontiers, err } -// AccountPending returns amount and source account. -type AccountPending struct { +// AccountReceivable returns amount and source account. +type AccountReceivable struct { Amount *RawAmount Source string } -// HashToPendingMap maps pending block hashes to amount and source account. -type HashToPendingMap map[string]AccountPending +// HashToReceivableMap maps receivable block hashes to amount and source account. +type HashToReceivableMap map[string]AccountReceivable // UnmarshalJSON sets *h to a copy of data. -func (h *HashToPendingMap) UnmarshalJSON(data []byte) (err error) { +func (h *HashToReceivableMap) UnmarshalJSON(data []byte) (err error) { var s string if err = json.Unmarshal(data, &s); err == nil && s == "" { return } - var v map[string]AccountPending + var v map[string]AccountReceivable err = json.Unmarshal(data, &v) *h = v return } -// AccountsPending returns a list of pending block hashes with amount and source accounts. -func (c *Client) AccountsPending(accounts []string, count int64) (pending map[string]HashToPendingMap, err error) { +// AccountsReceivable returns a list of receivable block hashes with amount and source accounts. +func (c *Client) AccountsReceivable(accounts []string, count int64) (receivable map[string]HashToReceivableMap, err error) { resp, err := c.send(map[string]interface{}{ - "action": "accounts_pending", + "action": "accounts_receivable", "accounts": accounts, "count": count, "include_only_confirmed": true, @@ -175,7 +175,7 @@ func (c *Client) AccountsPending(accounts []string, count int64) (pending map[st return } var v struct { - Blocks map[string]HashToPendingMap + Blocks map[string]HashToReceivableMap } err = json.Unmarshal(resp, &v) return v.Blocks, err @@ -243,7 +243,7 @@ func (c *Client) Ledger(account string, count int64, modifiedSince time.Time) (a "modified_since": modifiedSince.Unix(), "representative": true, "weight": true, - "pending": true, + "receivable": true, }) if err != nil { return @@ -281,3 +281,40 @@ func (c *Client) RepresentativesOnline() (representatives map[string]Representat err = json.Unmarshal(resp, &v) return v.Representatives, err } + +// V23.0+ methods + +// Receivable returns a list of block hashes which have not yet been received by this account. +func (c *Client) Receivable( + account string, count int64, includeActive bool, threshold string, +) (receivable HashToReceivableMap, err error) { + body := map[string]interface{}{ + "action": "receivable", + "account": account, + "include_only_confirmed": true, // it defaults to false for v22.0 and below + "source": true, + } + if count != 0 { + body["count"] = count + } + // include_active defaults to false + if includeActive != false { + body["include_active"] = true + } + if threshold != "" { + body["threshold"] = threshold + } + resp, err := c.send(body) + if err != nil { + return + } + var u struct{ Blocks string } + if err = json.Unmarshal(resp, &u); err == nil && u.Blocks == "" { + return + } + var v struct { + Blocks HashToReceivableMap + } + err = json.Unmarshal(resp, &v) + return v.Blocks, err +} diff --git a/rpc/account_test.go b/rpc/account_test.go index cda5184..b63e2b4 100644 --- a/rpc/account_test.go +++ b/rpc/account_test.go @@ -13,7 +13,7 @@ import ( const testAccount = "nano_1zcffp784drsmz4oksufxfjut1nb5yh6pg43a6h6bkos39zz19ed6a4r36ny" func getClient() *rpc.Client { - return &rpc.Client{URL: "https://mynano.ninja/api/node"} + return &rpc.Client{URL: "https://app.natrium.io/api"} } func assertEqualBig(t *testing.T, s string, z *big.Int) { @@ -28,10 +28,10 @@ func assertEqualBytes(t *testing.T, s string, b []byte) { } func TestAccountBalance(t *testing.T) { - balance, pending, err := getClient().AccountBalance(testAccount) + balance, receivable, err := getClient().AccountBalance(testAccount) require.Nil(t, err) assertEqualBig(t, "134000000000000000000000000", &balance.Int) - assertEqualBig(t, "0", &pending.Int) + assertEqualBig(t, "0", &receivable.Int) } func TestAccountHistory(t *testing.T) { @@ -100,7 +100,7 @@ func TestAccountsBalances(t *testing.T) { require.Nil(t, err) require.Len(t, balances, 1) assertEqualBig(t, "134000000000000000000000000", &balances[testAccount].Balance.Int) - assertEqualBig(t, "0", &balances[testAccount].Pending.Int) + assertEqualBig(t, "0", &balances[testAccount].Receivable.Int) } func TestAccountsFrontiers(t *testing.T) { @@ -110,16 +110,16 @@ func TestAccountsFrontiers(t *testing.T) { assertEqualBytes(t, "8C1B5D4BBE27F05C7A888D1E691A07C550A81AFEE16D913EE21E1093888B82FD", frontiers[testAccount]) } -func TestAccountsPending(t *testing.T) { - pendings, err := getClient().AccountsPending([]string{ +func TestAccountsReceivable(t *testing.T) { + receivables, err := getClient().AccountsReceivable([]string{ testAccount, "nano_159m8t4iedstzcaacikb9hdkhbcxcqzfbw56dutay8ceqagq9wxpsk9ftfq9"}, 1) require.Nil(t, err) - require.Len(t, pendings, 1) - blocks := pendings["nano_159m8t4iedstzcaacikb9hdkhbcxcqzfbw56dutay8ceqagq9wxpsk9ftfq9"] + require.Len(t, receivables, 1) + blocks := receivables["nano_159m8t4iedstzcaacikb9hdkhbcxcqzfbw56dutay8ceqagq9wxpsk9ftfq9"] require.Len(t, blocks, 1) - pending := blocks["96D8422D1CB676EF1B62A313865626A7725C3B9BB5B875601A1460ACF30B5322"] - assertEqualBig(t, "123000000000000000000000000", &pending.Amount.Int) - assert.Equal(t, "nano_3kwppxjcggzs65fjh771ch6dbuic3xthsn5wsg6i5537jacw7m493ra8574x", pending.Source) + receivable := blocks["96D8422D1CB676EF1B62A313865626A7725C3B9BB5B875601A1460ACF30B5322"] + assertEqualBig(t, "123000000000000000000000000", &receivable.Amount.Int) + assert.Equal(t, "nano_3kwppxjcggzs65fjh771ch6dbuic3xthsn5wsg6i5537jacw7m493ra8574x", receivable.Source) } func TestFrontierCount(t *testing.T) { diff --git a/rpc/types.go b/rpc/types.go index 8ae0bb5..cd5c4ea 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -54,7 +54,7 @@ type AccountInfo struct { AccountVersion uint64 `json:"account_version,string"` Representative string `json:"representative"` Weight *RawAmount `json:"weight"` - Pending *RawAmount `json:"pending"` + Receivable *RawAmount `json:"receivable"` } // Block corresponds to the JSON representation of a block. diff --git a/wallet/account.go b/wallet/account.go index 94d2e65..4dae8e3 100644 --- a/wallet/account.go +++ b/wallet/account.go @@ -28,8 +28,8 @@ func (a *Account) Index() uint32 { return a.index } -// Balance gets the confirmed and pending balances for account. -func (a *Account) Balance() (balance, pending *big.Int, err error) { +// Balance gets the confirmed and receivable balances for account. +func (a *Account) Balance() (balance, receivable *big.Int, err error) { b, p, err := a.w.RPC.AccountBalance(a.address) if err != nil { return @@ -76,17 +76,17 @@ func (a *Account) SendBlock(account string, amount *big.Int) (block *rpc.Block, return block, a.w.impl.signBlock(a, block) } -// ReceivePendings pockets all pending amounts. -func (a *Account) ReceivePendings() (err error) { - pendings, err := a.w.RPC.AccountsPending([]string{a.address}, -1) +// ReceiveReceivables pockets all receivable amounts. +func (a *Account) ReceiveReceivables() (err error) { + receivables, err := a.w.RPC.AccountsReceivable([]string{a.address}, -1) if err != nil { return } - return a.receivePendings(pendings[a.address]) + return a.receiveReceivables(receivables[a.address]) } -// ReceivePending pockets the specified link block. -func (a *Account) ReceivePending(link rpc.BlockHash) (hash rpc.BlockHash, err error) { +// ReceiveReceivable pockets the specified link block. +func (a *Account) ReceiveReceivable(link rpc.BlockHash) (hash rpc.BlockHash, err error) { info, err := a.w.RPC.AccountInfo(a.address) if err != nil { info.Balance = &rpc.RawAmount{} @@ -96,31 +96,31 @@ func (a *Account) ReceivePending(link rpc.BlockHash) (hash rpc.BlockHash, err er return } info.Balance.Add(&info.Balance.Int, &block.Amount.Int) - return a.receivePending(info, link) + return a.receiveReceivable(info, link) } -func (a *Account) receivePendings(pendings rpc.HashToPendingMap) (err error) { - if len(pendings) == 0 { +func (a *Account) receiveReceivables(receivables rpc.HashToReceivableMap) (err error) { + if len(receivables) == 0 { return } info, err := a.w.RPC.AccountInfo(a.address) if err != nil { info.Balance = &rpc.RawAmount{} } - for hash, pending := range pendings { + for hash, receivable := range receivables { var link rpc.BlockHash if link, err = hex.DecodeString(hash); err != nil { return } - info.Balance.Add(&info.Balance.Int, &pending.Amount.Int) - if info.Frontier, err = a.receivePending(info, link); err != nil { + info.Balance.Add(&info.Balance.Int, &receivable.Amount.Int) + if info.Frontier, err = a.receiveReceivable(info, link); err != nil { return } } return } -func (a *Account) receivePending(info rpc.AccountInfo, link rpc.BlockHash) (hash rpc.BlockHash, err error) { +func (a *Account) receiveReceivable(info rpc.AccountInfo, link rpc.BlockHash) (hash rpc.BlockHash, err error) { workHash := info.Frontier if info.Frontier == nil { info.Frontier = make(rpc.BlockHash, 32) diff --git a/wallet/ed25519/edwards25519/edwards25519.go b/wallet/ed25519/edwards25519/edwards25519.go index fd03c25..f57e53b 100644 --- a/wallet/ed25519/edwards25519/edwards25519.go +++ b/wallet/ed25519/edwards25519/edwards25519.go @@ -11,7 +11,7 @@ import "encoding/binary" // FieldElement represents an element of the field GF(2^255 - 19). An element // t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 -// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary dereceivable on // context. type FieldElement [10]int32 @@ -108,27 +108,29 @@ func FeFromBytes(dst *FieldElement, src *[32]byte) { // FeToBytes marshals h to s. // Preconditions: -// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. // // Write p=2^255-19; q=floor(h/p). // Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). // // Proof: -// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. -// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. // -// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). -// Then 0> 5) @@ -1449,11 +1464,13 @@ func ScMulAdd(s, a, b, c *[32]byte) { } // Input: -// s[0]+256*s[1]+...+256^63*s[63] = s +// +// s[0]+256*s[1]+...+256^63*s[63] = s // // Output: -// s[0]+256*s[1]+...+256^31*s[31] = s mod l -// where l = 2^252 + 27742317777372353535851937790883648493. +// +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. func ScReduce(out *[32]byte, s *[64]byte) { s0 := 2097151 & load3(s[:]) s1 := 2097151 & (load4(s[2:]) >> 5) diff --git a/wallet/wallet.go b/wallet/wallet.go index b4ae917..e7488c0 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -46,7 +46,7 @@ func newWallet(seed []byte) *Wallet { return &Wallet{ seed: seed, accounts: make(map[string]*Account), - RPC: rpc.Client{URL: "https://mynano.ninja/api/node"}, + RPC: rpc.Client{URL: "https://app.natrium.io/api"}, RPCWork: rpc.Client{URL: "http://[::1]:7076"}, impl: seedImpl{}, } @@ -72,7 +72,7 @@ func (w *Wallet) ScanForAccounts() (err error) { } i := len(accounts) - 1 for ; i >= 0; i-- { - if balances[accounts[i]].Pending.Sign() > 0 { + if balances[accounts[i]].Receivable.Sign() > 0 { break } if frontiers[accounts[i]] != nil { @@ -125,18 +125,18 @@ func (w *Wallet) GetAccounts() (accounts []*Account) { return } -// ReceivePendings pockets all pending amounts. -func (w *Wallet) ReceivePendings() (err error) { +// ReceiveReceivables pockets all receivable amounts. +func (w *Wallet) ReceiveReceivables() (err error) { accounts := make([]string, 0, len(w.accounts)) for address := range w.accounts { accounts = append(accounts, address) } - pendings, err := w.RPC.AccountsPending(accounts, -1) + receivables, err := w.RPC.AccountsReceivable(accounts, -1) if err != nil { return } - for account, pendings := range pendings { - if err = w.accounts[account].receivePendings(pendings); err != nil { + for account, receivables := range receivables { + if err = w.accounts[account].receiveReceivables(receivables); err != nil { return } }