-
Notifications
You must be signed in to change notification settings - Fork 12
/
commitment_api.go
157 lines (128 loc) · 5.84 KB
/
commitment_api.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
package engine
import (
"github.com/iotaledger/hive.go/ads"
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/iota-core/pkg/model"
iotago "github.com/iotaledger/iota.go/v4"
"github.com/iotaledger/iota.go/v4/merklehasher"
)
// CommitmentAPI is a wrapper for the Engine that provides access to the data of a committed slot.
type CommitmentAPI struct {
// engine is the Engine that is used to access the data.
engine *Engine
// CommitmentID is the index of the slot that is accessed.
CommitmentID iotago.CommitmentID
}
// NewCommitmentAPI creates a new CommitmentAPI.
func NewCommitmentAPI(engine *Engine, commitmentID iotago.CommitmentID) *CommitmentAPI {
return &CommitmentAPI{
engine: engine,
CommitmentID: commitmentID,
}
}
// Commitment returns the commitment of the slot.
func (c *CommitmentAPI) Commitment() (commitment *model.Commitment, err error) {
if commitment, err = c.engine.Storage.Commitments().Load(c.CommitmentID.Slot()); err != nil {
return nil, ierrors.Wrapf(err, "failed to load commitment for slot %d", c.CommitmentID)
}
if commitment.ID() != c.CommitmentID {
return nil, ierrors.Errorf("commitment in the store does not match the given commitmentID (%s != %s)", commitment.ID(), c.CommitmentID)
}
return commitment, nil
}
// Attestations returns the commitment, attestations and the merkle proof of the slot.
func (c *CommitmentAPI) Attestations() (commitment *model.Commitment, attestations []*iotago.Attestation, merkleProof *merklehasher.Proof[iotago.Identifier], err error) {
commitment, err = c.Commitment()
if err != nil {
return nil, nil, nil, ierrors.Wrap(err, "failed to load commitment")
}
if attestations, err = c.engine.Attestations.Get(c.CommitmentID.Slot()); err != nil {
return nil, nil, nil, ierrors.Wrap(err, "failed to load attestations")
}
rootsStorage, err := c.engine.Storage.Roots(c.CommitmentID.Slot())
if err != nil {
return nil, nil, nil, ierrors.Wrap(err, "failed to load roots storage")
}
roots, exists, err := rootsStorage.Load(c.CommitmentID)
if err != nil {
return nil, nil, nil, ierrors.Wrap(err, "failed to load roots")
} else if !exists {
return nil, nil, nil, ierrors.New("roots not found")
}
return commitment, attestations, roots.AttestationsProof(), nil
}
// Mutations returns all accepted block IDs, the tangle proof, all accepted transaction IDs and the ledger state
// mutation proof of the slot.
func (c *CommitmentAPI) Mutations() (acceptedBlocksBySlotCommitment map[iotago.CommitmentID]iotago.BlockIDs, acceptedBlocksProof *merklehasher.Proof[iotago.Identifier], acceptedTransactionIDs iotago.TransactionIDs, acceptedTransactionsProof *merklehasher.Proof[iotago.Identifier], err error) {
if acceptedBlocksBySlotCommitment, err = c.BlocksIDsBySlotCommitmentID(); err != nil {
return nil, nil, nil, nil, ierrors.Wrap(err, "failed to get block ids")
}
roots, err := c.Roots()
if err != nil {
return nil, nil, nil, nil, ierrors.Wrap(err, "failed to get roots")
}
acceptedTransactionIDs, err = c.TransactionIDs()
if err != nil {
return nil, nil, nil, nil, ierrors.Wrap(err, "failed to get transaction ids")
}
return acceptedBlocksBySlotCommitment, roots.TangleProof(), acceptedTransactionIDs, roots.MutationProof(), nil
}
// Roots returns the roots of the slot.
func (c *CommitmentAPI) Roots() (committedRoots *iotago.Roots, err error) {
if c.engine.SyncManager.LatestCommitment().Slot() < c.CommitmentID.Slot() {
return nil, ierrors.Errorf("slot %d is not committed yet", c.CommitmentID.Slot())
}
rootsStorage, err := c.engine.Storage.Roots(c.CommitmentID.Slot())
if err != nil {
return nil, ierrors.Errorf("no roots storage for slot %d", c.CommitmentID.Slot())
}
roots, _, err := rootsStorage.Load(c.CommitmentID)
if err != nil {
return nil, ierrors.Wrapf(err, "failed to load roots for slot %d", c.CommitmentID.Slot())
} else if roots == nil {
return nil, ierrors.Errorf("roots for slot %d are not known, yet", c.CommitmentID.Slot())
}
return roots, nil
}
// BlocksIDsBySlotCommitmentID returns the accepted block IDs of the slot grouped by their SlotCommitmentID.
func (c *CommitmentAPI) BlocksIDsBySlotCommitmentID() (map[iotago.CommitmentID]iotago.BlockIDs, error) {
if c.engine.SyncManager.LatestCommitment().Slot() < c.CommitmentID.Slot() {
return nil, ierrors.Errorf("slot %d is not committed yet", c.CommitmentID.Slot())
}
store, err := c.engine.Storage.Blocks(c.CommitmentID.Slot())
if err != nil {
return nil, ierrors.Errorf("failed to get block store of slot index %d", c.CommitmentID.Slot())
}
blockIDsBySlotCommitmentID := make(map[iotago.CommitmentID]iotago.BlockIDs)
if err := store.ForEachBlockInSlot(func(block *model.Block) error {
blockIDsBySlotCommitmentID[block.SlotCommitmentID()] = append(blockIDsBySlotCommitmentID[block.SlotCommitmentID()], block.ID())
return nil
}); err != nil {
return nil, ierrors.Wrapf(err, "failed to iterate over blocks of slot %d", c.CommitmentID.Slot())
}
return blockIDsBySlotCommitmentID, nil
}
func (c *CommitmentAPI) TransactionIDs() (iotago.TransactionIDs, error) {
if c.engine.SyncManager.LatestCommitment().Slot() < c.CommitmentID.Slot() {
return nil, ierrors.Errorf("slot %d is not committed yet", c.CommitmentID.Slot())
}
store, err := c.engine.Storage.Mutations(c.CommitmentID.Slot())
if err != nil {
return nil, ierrors.Errorf("failed to get mutations of slot index %d", c.CommitmentID.Slot())
}
set := ads.NewSet[iotago.Identifier](
store,
iotago.Identifier.Bytes,
iotago.IdentifierFromBytes,
iotago.TransactionID.Bytes,
iotago.TransactionIDFromBytes,
)
transactionIDs := make(iotago.TransactionIDs, 0, set.Size())
if err = set.Stream(func(txID iotago.TransactionID) error {
transactionIDs = append(transactionIDs, txID)
return nil
}); err != nil {
return nil, ierrors.Wrapf(err, "failed to iterate over mutations of slot %d", c.CommitmentID.Slot())
}
return transactionIDs, nil
}