-
Notifications
You must be signed in to change notification settings - Fork 71
/
account.go
106 lines (83 loc) · 2.67 KB
/
account.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
package database
import (
"crypto/ecdsa"
"errors"
"github.com/ethereum/go-ethereum/crypto"
)
// Account represents information stored in the database for an individual account.
type Account struct {
AccountID AccountID
Nonce uint64
Balance uint64
}
// newAccount constructs a new account value for use.
func newAccount(accountID AccountID, balance uint64) Account {
return Account{
AccountID: accountID,
Balance: balance,
}
}
// =============================================================================
// AccountID represents an account id that is used to sign transactions and is
// associated with transactions on the blockchain. This will be the last 20
// bytes of the public key.
type AccountID string
// ToAccountID converts a hex-encoded string to an account and validates the
// hex-encoded string is formatted correctly.
func ToAccountID(hex string) (AccountID, error) {
a := AccountID(hex)
if !a.IsAccountID() {
return "", errors.New("invalid account format")
}
return a, nil
}
// PublicKeyToAccountID converts the public key to an account value.
func PublicKeyToAccountID(pk ecdsa.PublicKey) AccountID {
return AccountID(crypto.PubkeyToAddress(pk).String())
}
// IsAccountID verifies whether the underlying data represents a valid
// hex-encoded account.
func (a AccountID) IsAccountID() bool {
const addressLength = 20
if has0xPrefix(a) {
a = a[2:]
}
return len(a) == 2*addressLength && isHex(a)
}
// =============================================================================
// has0xPrefix validates the account starts with a 0x.
func has0xPrefix(a AccountID) bool {
return len(a) >= 2 && a[0] == '0' && (a[1] == 'x' || a[1] == 'X')
}
// isHex validates whether each byte is valid hexadecimal string.
func isHex(a AccountID) bool {
if len(a)%2 != 0 {
return false
}
for _, c := range []byte(a) {
if !isHexCharacter(c) {
return false
}
}
return true
}
// isHexCharacter returns bool of c being a valid hexadecimal.
func isHexCharacter(c byte) bool {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
}
// =============================================================================
// byAccount provides sorting support by the account id value.
type byAccount []Account
// Len returns the number of transactions in the list.
func (ba byAccount) Len() int {
return len(ba)
}
// Less helps to sort the list by account id in ascending order to keep the
// accounts in the right order of processing.
func (ba byAccount) Less(i, j int) bool {
return ba[i].AccountID < ba[j].AccountID
}
// Swap moves accounts in the order of the account id value.
func (ba byAccount) Swap(i, j int) {
ba[i], ba[j] = ba[j], ba[i]
}