-
Notifications
You must be signed in to change notification settings - Fork 4
/
marshal.go
141 lines (130 loc) · 3.7 KB
/
marshal.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
package account
import (
"encoding/binary"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/multiformats/go-multihash"
dageth "github.com/vulcanize/go-codec-dageth"
"github.com/vulcanize/go-codec-dageth/shared"
)
// Encode provides an IPLD codec encode interface for eth state account IPLDs.
// This function is registered via the go-ipld-prime link loader for multicodec
// code 0x97 when this package is invoked via init.
func Encode(node ipld.Node, w io.Writer) error {
// 1KiB can be allocated on the stack, and covers most small nodes
// without having to grow the buffer and cause allocations.
enc := make([]byte, 0, 1024)
enc, err := AppendEncode(enc, node)
if err != nil {
return err
}
_, err = w.Write(enc)
return err
}
// AppendEncode is like Encode, but it uses a destination buffer directly.
// This means less copying of bytes, and if the destination has enough capacity,
// fewer allocations.
func AppendEncode(enc []byte, inNode ipld.Node) ([]byte, error) {
account := new(types.StateAccount)
if err := EncodeAccount(account, inNode); err != nil {
return enc, err
}
wbs := shared.NewWriteableByteSlice(&enc)
if err := rlp.Encode(wbs, account); err != nil {
return enc, fmt.Errorf("invalid DAG-ETH Account form (unable to RLP encode account: %v)", err)
}
return enc, nil
}
// EncodeAccount packs the node into the provided go-ethereum Account
func EncodeAccount(header *types.StateAccount, inNode ipld.Node) error {
// Wrap in a typed node for some basic schema form checking
builder := dageth.Type.Account.NewBuilder()
if err := builder.AssignNode(inNode); err != nil {
return err
}
node := builder.Build()
for _, pFunc := range requiredPackFuncs {
if err := pFunc(header, node); err != nil {
return fmt.Errorf("invalid DAG-ETH Account form (%v)", err)
}
}
return nil
}
var requiredPackFuncs = []func(*types.StateAccount, ipld.Node) error{
packNonce,
packBalance,
packStorageRootCID,
packCodeCID,
}
func packNonce(account *types.StateAccount, node ipld.Node) error {
n, err := node.LookupByString("Nonce")
if err != nil {
return err
}
nBytes, err := n.AsBytes()
if err != nil {
return err
}
account.Nonce = binary.BigEndian.Uint64(nBytes)
return nil
}
func packBalance(account *types.StateAccount, node ipld.Node) error {
b, err := node.LookupByString("Balance")
if err != nil {
return err
}
bBytes, err := b.AsBytes()
if err != nil {
return err
}
account.Balance = new(big.Int).SetBytes(bBytes)
return nil
}
func packStorageRootCID(account *types.StateAccount, node ipld.Node) error {
srCID, err := node.LookupByString("StorageRootCID")
if err != nil {
return err
}
srLink, err := srCID.AsLink()
if err != nil {
return err
}
srCIDLink, ok := srLink.(cidlink.Link)
if !ok {
return fmt.Errorf("account must have a StateRootCID")
}
srMh := srCIDLink.Hash()
decodedSrMh, err := multihash.Decode(srMh)
if err != nil {
return fmt.Errorf("unable to decode StorageRootCID multihash: %v", err)
}
account.Root = common.BytesToHash(decodedSrMh.Digest)
return nil
}
func packCodeCID(account *types.StateAccount, node ipld.Node) error {
cCID, err := node.LookupByString("CodeCID")
if err != nil {
return err
}
cLink, err := cCID.AsLink()
if err != nil {
return err
}
cCIDLink, ok := cLink.(cidlink.Link)
if !ok {
return fmt.Errorf("account must have a CodeCID")
}
cMh := cCIDLink.Hash()
decodedCMh, err := multihash.Decode(cMh)
if err != nil {
return fmt.Errorf("unable to decode CodeCID multihash: %v", err)
}
account.CodeHash = decodedCMh.Digest
return nil
}