/
state_serializer.go
95 lines (81 loc) · 2.14 KB
/
state_serializer.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
package state
import (
"crypto"
"fmt"
"github.com/alphabill-org/alphabill/tree/avl"
"github.com/alphabill-org/alphabill/tree/mt"
"github.com/alphabill-org/alphabill/types"
"github.com/fxamacker/cbor/v2"
)
const CBORChecksumLength = 5
type (
header struct {
_ struct{} `cbor:",toarray"`
UnicityCertificate *types.UnicityCertificate
NodeRecordCount uint64
}
nodeRecord struct {
_ struct{} `cbor:",toarray"`
UnitID types.UnitID
OwnerCondition []byte
UnitData cbor.RawMessage
UnitLedgerHeadHash []byte
UnitTreePath []*mt.PathItem
HasLeft bool
HasRight bool
}
stateSerializer struct {
encoder *cbor.Encoder
hashAlgorithm crypto.Hash
err error
}
)
func newStateSerializer(encoder *cbor.Encoder, hashAlgorithm crypto.Hash) *stateSerializer {
return &stateSerializer{
encoder: encoder,
hashAlgorithm: hashAlgorithm,
}
}
func (s *stateSerializer) Traverse(n *avl.Node[types.UnitID, *Unit]) {
if n == nil || s.err != nil {
return
}
s.Traverse(n.Left())
s.Traverse(n.Right())
s.WriteNode(n)
}
func (s *stateSerializer) WriteNode(n *avl.Node[types.UnitID, *Unit]) {
if s.err != nil {
return
}
unit := n.Value()
logSize := len(unit.logs)
if logSize == 0 {
s.err = fmt.Errorf("unit state log is empty")
}
latestLog := unit.logs[logSize-1]
unitDataBytes, err := cbor.Marshal(latestLog.NewUnitData)
if err != nil {
s.err = fmt.Errorf("unable to encode unit data: %w", err)
return
}
merkleTree := mt.New(s.hashAlgorithm, unit.logs)
unitTreePath, err := merkleTree.GetMerklePath(logSize - 1)
if err != nil {
s.err = fmt.Errorf("unable to extract unit tree path: %w", err)
return
}
nr := &nodeRecord{
UnitID: n.Key(),
OwnerCondition: latestLog.NewBearer,
UnitLedgerHeadHash: latestLog.UnitLedgerHeadHash,
UnitData: unitDataBytes,
UnitTreePath: unitTreePath,
HasLeft: n.Left() != nil,
HasRight: n.Right() != nil,
}
if err = s.encoder.Encode(nr); err != nil {
s.err = fmt.Errorf("unable to encode node record: %w", err)
return
}
}