-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathaccount_info.go
138 lines (129 loc) · 3.88 KB
/
account_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package atto
import (
"fmt"
"math/big"
"strings"
)
// AccountInfo holds the basic data needed for Block creation.
type AccountInfo struct {
// Ignore this field. It only exists because of
// https://github.com/nanocurrency/nano-node/issues/1782.
Error string `json:"error"`
Frontier string `json:"frontier"`
Representative string `json:"representative"`
Balance string `json:"balance"`
PublicKey *big.Int `json:"-"`
Address string `json:"-"`
}
// Send creates a send block, which will still be missing its signature
// and work. The Frontier and Balance of the AccountInfo will be
// updated. The amount is interpreted as Nano, not raw!
func (i *AccountInfo) Send(amount, toAddr string) (Block, error) {
balance, err := getBalanceAfterSend(i.Balance, amount)
if err != nil {
return Block{}, err
}
recipientNumber, err := getPublicKeyFromAddress(toAddr)
if err != nil {
return Block{}, err
}
recipientBytes := bigIntToBytes(recipientNumber, 32)
block := Block{
Type: "state",
SubType: SubTypeSend,
Account: i.Address,
Previous: i.Frontier,
Representative: i.Representative,
Balance: balance.String(),
Link: fmt.Sprintf("%064X", recipientBytes),
}
hash, err := block.Hash()
if err != nil {
return Block{}, err
}
i.Frontier = hash
i.Balance = block.Balance
return block, err
}
func getBalanceAfterSend(oldBalance string, amount string) (*big.Int, error) {
balance, ok := big.NewInt(0).SetString(oldBalance, 10)
if !ok {
err := fmt.Errorf("cannot parse '%s' as an integer", oldBalance)
return nil, err
}
amountRaw, err := nanoToRaw(amount)
if err != nil {
return nil, err
}
return balance.Sub(balance, amountRaw), nil
}
func nanoToRaw(amountString string) (*big.Int, error) {
i := strings.Index(amountString, ".")
missingZerosUntilRaw := 30
if i > -1 {
missingZerosUntilRaw = 31 + i - len(amountString)
amountString = amountString[:i] + amountString[i+1:] // Remove "."
}
amountString += strings.Repeat("0", missingZerosUntilRaw)
amount, ok := big.NewInt(0).SetString(amountString, 10)
if !ok {
return nil, fmt.Errorf("cannot parse '%s' as an interger", amountString)
}
return amount, nil
}
// Change creates a change block, which will still be missing its
// signature and work. The Frontier and Representative of the
// AccountInfo will be updated.
func (i *AccountInfo) Change(representative string) (Block, error) {
block := Block{
Type: "state",
SubType: SubTypeChange,
Account: i.Address,
Previous: i.Frontier,
Representative: representative,
Balance: i.Balance,
Link: "0000000000000000000000000000000000000000000000000000000000000000",
}
hash, err := block.Hash()
if err != nil {
return Block{}, err
}
i.Frontier = hash
return block, err
}
// Receive creates a receive block, which will still be missing its
// signature and work. The Frontier and Balance of the AccountInfo will
// be updated.
func (i *AccountInfo) Receive(receivable Receivable) (Block, error) {
updatedBalance, ok := big.NewInt(0).SetString(i.Balance, 10)
if !ok {
err := fmt.Errorf("cannot parse '%s' as an integer", i.Balance)
return Block{}, err
}
amount, ok := big.NewInt(0).SetString(receivable.Amount, 10)
if !ok {
err := fmt.Errorf("cannot parse '%s' as an integer", receivable.Amount)
return Block{}, err
}
if amount.Sign() < 1 {
err := fmt.Errorf("amount '%s' is not positive", receivable.Amount)
return Block{}, err
}
updatedBalance.Add(updatedBalance, amount)
block := Block{
Type: "state",
SubType: SubTypeReceive,
Account: i.Address,
Previous: i.Frontier,
Representative: i.Representative,
Balance: updatedBalance.String(),
Link: receivable.Hash,
}
hash, err := block.Hash()
if err != nil {
return Block{}, err
}
i.Frontier = hash
i.Balance = block.Balance
return block, err
}