-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathaccount.go
162 lines (136 loc) · 4.39 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
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package libra
import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
)
const (
// See https://github.com/perfectmak/libra-core/blob/6dc45f7b72aee0162d52a9d53d99cdae1adae6f1/lib/constants/PathValues.ts
accResourceKey = "01217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97"
)
// AccountState represents the state of an account.
type AccountState struct {
// The whole account state as raw bytes
Blob []byte
// The account resource with balance etc.
AccountResource AccountResource
// TODO: AccountEvents?
}
// FromAccountStateBlob converts an account state blob into an object of the AccountState struct.
func FromAccountStateBlob(accountStateBlob []byte) (AccountState, error) {
result := AccountState{
Blob: accountStateBlob,
}
r := bytes.NewReader(accountStateBlob)
// Inspired by https://github.com/perfectmak/libra-core/blob/6dc45f7b72aee0162d52a9d53d99cdae1adae6f1/lib/client.ts#L250
var mapEntryCount uint32
err := binary.Read(r, binary.LittleEndian, &mapEntryCount)
if err != nil {
return result, err
}
m := make(map[string][]byte, mapEntryCount)
// For now we only decode the account state.
// Go through the whole blob to find it (it has a specific map key).
// TODO: Also take care of events.
accResourceKeyFound := false
for mapEntryNo := uint32(1); mapEntryNo <= mapEntryCount; mapEntryNo++ {
var mapKeyLen uint32
err := binary.Read(r, binary.LittleEndian, &mapKeyLen)
if err != nil {
return result, err
}
mapKey := make([]byte, mapKeyLen)
err = binary.Read(r, binary.LittleEndian, &mapKey)
if err != nil {
return result, err
}
var mapValLength uint32
err = binary.Read(r, binary.LittleEndian, &mapValLength)
if err != nil {
return result, err
}
mapVal := make([]byte, mapValLength)
err = binary.Read(r, binary.LittleEndian, &mapVal)
if err != nil {
return result, err
}
mapKeyAsString := hex.EncodeToString(mapKey)
m[mapKeyAsString] = mapVal
// TODO: Remove when adding handling of events
if mapKeyAsString == accResourceKey {
accResourceKeyFound = true
break
}
}
if !accResourceKeyFound {
return result, errors.New("The account state blob didn't contain the data of an account resource or there was an error decoding it")
}
accResource, err := FromAccountResourceBlob(m[accResourceKey])
if err != nil {
return result, err
}
result.AccountResource = accResource
return result, nil
}
// AccountResource represents an account with its balance etc.
type AccountResource struct {
AuthKey []byte
Balance uint64
ReceivedEvents uint64
SentEvents uint64
SequenceNo uint64
}
// String formats the account state similarly to the Libra CLI.
// Numbers are formatted as string because the numbers are uint64,
// whose max value exceeds JSON's "safe integer",
// which can lead to parsing errors.
//
// Info about JSON's "safe integer":
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
func (ar AccountResource) String() string {
return fmt.Sprintf("{\"authentication_key\": \"0x%x\", \"balance\": \"%d\", \"received_events_count\": \"%d\", \"sent_events_count\": \"%d\", \"sequence_number\": \"%d\"}",
ar.AuthKey, ar.Balance, ar.ReceivedEvents, ar.SentEvents, ar.SequenceNo)
}
// FromAccountResourceBlob converts an account resource blob into an object of the AccountState struct.
func FromAccountResourceBlob(accountResourceBlob []byte) (AccountResource, error) {
result := AccountResource{}
r := bytes.NewReader(accountResourceBlob)
var authKeyLen uint32
err := binary.Read(r, binary.LittleEndian, &authKeyLen)
if err != nil {
return result, err
}
authKey := make([]byte, authKeyLen)
err = binary.Read(r, binary.LittleEndian, &authKey)
if err != nil {
return result, err
}
result.AuthKey = authKey
var balance uint64
err = binary.Read(r, binary.LittleEndian, &balance)
if err != nil {
return result, err
}
result.Balance = balance
var receivedEvents uint64
err = binary.Read(r, binary.LittleEndian, &receivedEvents)
if err != nil {
return result, err
}
result.ReceivedEvents = receivedEvents
var sentEvents uint64
err = binary.Read(r, binary.LittleEndian, &sentEvents)
if err != nil {
return result, err
}
result.SentEvents = sentEvents
var sequenceNo uint64
err = binary.Read(r, binary.LittleEndian, &sequenceNo)
if err != nil {
return result, err
}
result.SequenceNo = sequenceNo
return result, nil
}