• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

razor-network / oracle-node / 11380926803

17 Oct 2024 08:09AM UTC coverage: 80.35% (-0.02%) from 80.365%
11380926803

push

github

web-flow
feat: added commitment verification layer for data during reveal after removing waitForBlockCompletion check for voting transactions (#1254)

* refactor: added verification layer on commit data from memory

* refactor: removed waitForBlockCompletion from propose and reveal

* fix: returned err instead of nil in GetConfirmedBlock

* reafctor: fixed tests

* refactor: fixed lint errors

* fix: returned supported struct type and added a condition to attempt confirmBlock when node just started voting

* refactor: fixed tests after rebasing

* refactor: removed commented unwanted tests

* refactor: Fetched selected commit data first and than applied commitment verification

* feat: saved commitment in the memory/file along with commit data and reused it in reveal

135 of 152 new or added lines in 6 files covered. (88.82%)

7 existing lines in 1 file now uncovered.

6559 of 8163 relevant lines covered (80.35%)

477.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.21
/cmd/commit.go
1
//Package cmd provides all functions related to command line
2
package cmd
3

4
import (
5
        "context"
6
        "encoding/hex"
7
        "errors"
8
        Types "github.com/ethereum/go-ethereum/core/types"
9
        "math/big"
10
        "razor/core"
11
        "razor/core/types"
12
        "razor/pkg/bindings"
13
        "razor/utils"
14
        "sync"
15

16
        "github.com/ethereum/go-ethereum/common"
17
        "github.com/ethereum/go-ethereum/ethclient"
18
        solsha3 "github.com/miguelmota/go-solidity-sha3"
19
)
20

21
/*
22
GetSalt calculates the salt on the basis of previous epoch and the medians of the previous epoch.
23
If the previous epoch doesn't contain any medians, then the value is fetched from the smart contract.
24
*/
25
func (*UtilsStruct) GetSalt(ctx context.Context, client *ethclient.Client, epoch uint32) ([32]byte, error) {
6✔
26
        previousEpoch := epoch - 1
6✔
27
        log.Debug("GetSalt: Previous epoch: ", previousEpoch)
6✔
28
        numProposedBlock, err := razorUtils.GetNumberOfProposedBlocks(ctx, client, previousEpoch)
6✔
29
        if err != nil {
7✔
30
                return [32]byte{}, err
1✔
31
        }
1✔
32
        log.Debug("GetSalt: Number of proposed blocks: ", numProposedBlock)
5✔
33
        blockIndexToBeConfirmed, err := razorUtils.GetBlockIndexToBeConfirmed(ctx, client)
5✔
34
        if err != nil {
6✔
35
                return [32]byte{}, err
1✔
36
        }
1✔
37
        log.Debug("GetSalt: Block Index to be confirmed: ", blockIndexToBeConfirmed)
4✔
38
        if numProposedBlock == 0 || (numProposedBlock > 0 && blockIndexToBeConfirmed < 0) {
5✔
39
                return utils.VoteManagerInterface.GetSaltFromBlockchain(client)
1✔
40
        }
1✔
41
        blockId, err := razorUtils.GetSortedProposedBlockId(ctx, client, previousEpoch, big.NewInt(int64(blockIndexToBeConfirmed)))
3✔
42
        if err != nil {
4✔
43
                return [32]byte{}, errors.New("Error in getting blockId: " + err.Error())
1✔
44
        }
1✔
45
        log.Debug("GetSalt: Block Id: ", blockId)
2✔
46
        previousBlock, err := razorUtils.GetProposedBlock(ctx, client, previousEpoch, blockId)
2✔
47
        if err != nil {
3✔
48
                return [32]byte{}, errors.New("Error in getting previous block: " + err.Error())
1✔
49
        }
1✔
50
        log.Debug("GetSalt: PreviousBlock: ", previousBlock)
1✔
51
        log.Debugf("GetSalt: Calling CalculateSalt() with arguments previous epoch = %d, previous block medians = %s", previousEpoch, previousBlock.Medians)
1✔
52
        return razorUtils.CalculateSalt(previousEpoch, previousBlock.Medians), nil
1✔
53
}
54

55
/*
56
HandleCommitState fetches the collections assigned to the staker and creates the leaves required for the merkle tree generation.
57
Values for only the collections assigned to the staker is fetched for others, 0 is added to the leaves of tree.
58
*/
59
func (*UtilsStruct) HandleCommitState(ctx context.Context, client *ethclient.Client, epoch uint32, seed []byte, commitParams *types.CommitParams, rogueData types.Rogue) (types.CommitData, error) {
6✔
60
        numActiveCollections, err := razorUtils.GetNumActiveCollections(ctx, client)
6✔
61
        if err != nil {
7✔
62
                return types.CommitData{}, err
1✔
63
        }
1✔
64
        log.Debug("HandleCommitState: Number of active collections: ", numActiveCollections)
5✔
65
        log.Debugf("HandleCommitState: Calling GetAssignedCollections() with arguments number of active collections = %d", numActiveCollections)
5✔
66
        assignedCollections, seqAllottedCollections, err := razorUtils.GetAssignedCollections(ctx, client, numActiveCollections, seed)
5✔
67
        if err != nil {
6✔
68
                return types.CommitData{}, err
1✔
69
        }
1✔
70

71
        leavesOfTree := make([]*big.Int, numActiveCollections)
4✔
72
        results := make(chan types.CollectionResult, numActiveCollections)
4✔
73
        errChan := make(chan error, numActiveCollections)
4✔
74

4✔
75
        defer close(results)
4✔
76
        defer close(errChan)
4✔
77

4✔
78
        var wg sync.WaitGroup
4✔
79

4✔
80
        // Clean up any expired API results cache data before performing the commit
4✔
81
        commitParams.LocalCache.Cleanup()
4✔
82

4✔
83
        log.Debug("Iterating over all the collections...")
4✔
84
        for i := 0; i < int(numActiveCollections); i++ {
16✔
85
                wg.Add(1)
12✔
86
                go func(i int) {
24✔
87
                        defer wg.Done()
12✔
88
                        var leaf *big.Int
12✔
89

12✔
90
                        log.Debugf("HandleCommitState: Is the collection at iterating index %v assigned: %v ", i, assignedCollections[i])
12✔
91
                        if assignedCollections[i] {
20✔
92
                                collectionId, err := razorUtils.GetCollectionIdFromIndex(ctx, client, uint16(i))
8✔
93
                                if err != nil {
10✔
94
                                        log.Error("Error in getting collection ID: ", err)
2✔
95
                                        errChan <- err
2✔
96
                                        return
2✔
97
                                }
2✔
98
                                collectionData, err := razorUtils.GetAggregatedDataOfCollection(ctx, client, collectionId, epoch, commitParams)
6✔
99
                                if err != nil {
8✔
100
                                        log.Error("Error in getting aggregated data of collection: ", err)
2✔
101
                                        errChan <- err
2✔
102
                                        return
2✔
103
                                }
2✔
104
                                if rogueData.IsRogue && utils.Contains(rogueData.RogueMode, "commit") {
6✔
105
                                        log.Warn("YOU ARE COMMITTING VALUES IN ROGUE MODE, THIS CAN INCUR PENALTIES!")
2✔
106
                                        collectionData = razorUtils.GetRogueRandomValue(100000)
2✔
107
                                        log.Debug("HandleCommitState: Collection data in rogue mode: ", collectionData)
2✔
108
                                }
2✔
109
                                log.Debugf("HandleCommitState: Data of collection %d: %s", collectionId, collectionData)
4✔
110
                                leaf = collectionData
4✔
111
                        } else {
4✔
112
                                leaf = big.NewInt(0)
4✔
113
                        }
4✔
114
                        log.Debugf("Sending index: %v,  leaf data: %v to results channel", i, leaf)
8✔
115
                        results <- types.CollectionResult{Index: i, Leaf: leaf}
8✔
116
                }(i)
117
        }
118

119
        wg.Wait()
4✔
120

4✔
121
        for i := 0; i < int(numActiveCollections); i++ {
13✔
122
                select {
9✔
123
                case result := <-results:
7✔
124
                        log.Infof("Received from results: Index: %d, Leaf: %v", result.Index, result.Leaf)
7✔
125
                        leavesOfTree[result.Index] = result.Leaf
7✔
126
                case err := <-errChan:
2✔
127
                        if err != nil {
4✔
128
                                // Returning the first error from the error channel
2✔
129
                                log.Error("Error in getting collection data: ", err)
2✔
130
                                return types.CommitData{}, err
2✔
131
                        }
2✔
132
                }
133
        }
134

135
        log.Debug("HandleCommitState: Assigned Collections: ", assignedCollections)
2✔
136
        log.Debug("HandleCommitState: SeqAllottedCollections: ", seqAllottedCollections)
2✔
137
        log.Debug("HandleCommitState: Leaves: ", leavesOfTree)
2✔
138

2✔
139
        return types.CommitData{
2✔
140
                AssignedCollections:    assignedCollections,
2✔
141
                SeqAllottedCollections: seqAllottedCollections,
2✔
142
                Leaves:                 leavesOfTree,
2✔
143
        }, nil
2✔
144
}
145

146
/*
147
Commit finally commits the data to the smart contract. It calculates the commitment to send using the merkle tree root and the seed.
148
*/
149
func (*UtilsStruct) Commit(ctx context.Context, client *ethclient.Client, config types.Configurations, account types.Account, epoch uint32, latestHeader *Types.Header, stateBuffer uint64, commitmentToSend [32]byte) (common.Hash, error) {
3✔
150
        if state, err := razorUtils.GetBufferedState(latestHeader, stateBuffer, config.BufferPercent); err != nil || state != 0 {
4✔
151
                log.Error("Not commit state")
1✔
152
                return core.NilHash, err
1✔
153
        }
1✔
154

155
        txnOpts := razorUtils.GetTxnOpts(ctx, types.TransactionOptions{
2✔
156
                Client:          client,
2✔
157
                ChainId:         core.ChainId,
2✔
158
                Config:          config,
2✔
159
                ContractAddress: core.VoteManagerAddress,
2✔
160
                ABI:             bindings.VoteManagerMetaData.ABI,
2✔
161
                MethodName:      "commit",
2✔
162
                Parameters:      []interface{}{epoch, commitmentToSend},
2✔
163
                Account:         account,
2✔
164
        })
2✔
165

2✔
166
        log.Info("Commitment sent...")
2✔
167
        log.Debugf("Executing Commit transaction with epoch = %d, commitmentToSend = %v", epoch, commitmentToSend)
2✔
168
        txn, err := voteManagerUtils.Commit(client, txnOpts, epoch, commitmentToSend)
2✔
169
        if err != nil {
3✔
170
                return core.NilHash, err
1✔
171
        }
1✔
172
        txnHash := transactionUtils.Hash(txn)
1✔
173
        log.Info("Txn Hash: ", txnHash.Hex())
1✔
174
        return txnHash, nil
1✔
175
}
176

177
func CalculateSeed(ctx context.Context, client *ethclient.Client, account types.Account, keystorePath string, epoch uint32) ([]byte, error) {
10✔
178
        log.Debugf("CalculateSeed: Calling CalculateSecret() with arguments epoch = %d, keystorePath = %s, chainId = %s", epoch, keystorePath, core.ChainId)
10✔
179
        _, secret, err := cmdUtils.CalculateSecret(account, epoch, keystorePath, core.ChainId)
10✔
180
        if err != nil {
12✔
181
                return nil, err
2✔
182
        }
2✔
183
        log.Debugf("CalculateSeed: Getting Salt for current epoch %d...", epoch)
8✔
184
        salt, err := cmdUtils.GetSalt(ctx, client, epoch)
8✔
185
        if err != nil {
10✔
186
                log.Error("Error in getting salt: ", err)
2✔
187
                return nil, err
2✔
188
        }
2✔
189
        seed := solsha3.SoliditySHA3([]string{"bytes32", "bytes32"}, []interface{}{"0x" + hex.EncodeToString(salt[:]), "0x" + hex.EncodeToString(secret)})
6✔
190
        return seed, nil
6✔
191
}
192

193
func CalculateCommitment(seed []byte, values []*big.Int) ([32]byte, error) {
8✔
194
        log.Debug("CalculateCommitment: Calling CreateMerkle() with argument Leaves = ", values)
8✔
195
        merkleTree, err := merkleUtils.CreateMerkle(values)
8✔
196
        if err != nil {
13✔
197
                return [32]byte{}, errors.New("Error in getting merkle tree: " + err.Error())
5✔
198
        }
5✔
199
        log.Debug("CalculateCommitment: Merkle Tree: ", merkleTree)
3✔
200
        log.Debug("CalculateCommitment: Calling GetMerkleRoot() for the merkle tree...")
3✔
201
        merkleRoot, err := merkleUtils.GetMerkleRoot(merkleTree)
3✔
202
        if err != nil {
3✔
203
                return [32]byte{}, errors.New("Error in getting root: " + err.Error())
×
204
        }
×
205
        commitment := solsha3.SoliditySHA3([]string{"bytes32", "bytes32"}, []interface{}{"0x" + hex.EncodeToString(merkleRoot[:]), "0x" + hex.EncodeToString(seed)})
3✔
206
        log.Debug("CalculateCommitment: Commitment: ", hex.EncodeToString(commitment))
3✔
207
        commitmentToSend := [32]byte{}
3✔
208
        copy(commitmentToSend[:], commitment)
3✔
209
        return commitmentToSend, nil
3✔
210
}
211

212
func VerifyCommitment(ctx context.Context, client *ethclient.Client, account types.Account, commitmentFetched [32]byte) (bool, error) {
8✔
213
        commitmentStruct, err := razorUtils.GetCommitment(ctx, client, account.Address)
8✔
214
        if err != nil {
9✔
215
                log.Error("Error in getting commitments: ", err)
1✔
216
                return false, err
1✔
217
        }
1✔
218
        log.Debugf("VerifyCommitment: CommitmentStruct: %+v", commitmentStruct)
7✔
219

7✔
220
        if commitmentFetched == commitmentStruct.CommitmentHash {
12✔
221
                log.Debug("VerifyCommitment: Commitment fetched from memory/file system for given values is EQUAL to commitment of the epoch")
5✔
222
                return true, nil
5✔
223
        }
5✔
224
        log.Debug("VerifyCommitment: Commitment fetched from memory/file system for given values DOES NOT MATCH with commitment in the epoch")
2✔
225
        return false, nil
2✔
226
}
227

228
func GetCommittedDataForEpoch(ctx context.Context, client *ethclient.Client, account types.Account, epoch uint32, rogueData types.Rogue) (types.CommitFileData, error) {
8✔
229
        // Attempt to fetch global commit data from memory if epoch matches
8✔
230
        if globalCommitDataStruct.Epoch == epoch {
12✔
231
                log.Debugf("Epoch in global commit data is equal to current epoch %v. Fetching commit data from memory!", epoch)
4✔
232
        } else {
8✔
233
                // Fetch from file if memory data is outdated
4✔
234
                log.Debugf("GetCommittedDataForEpoch: Global commit data epoch %v doesn't match current epoch %v. Fetching from file!", globalCommitDataStruct.Epoch, epoch)
4✔
235
                log.Info("Getting the commit data from file...")
4✔
236
                fileName, err := pathUtils.GetCommitDataFileName(account.Address)
4✔
237
                if err != nil {
5✔
238
                        return types.CommitFileData{}, err
1✔
239
                }
1✔
240

241
                log.Debug("GetCommittedDataForEpoch: Commit data file path: ", fileName)
3✔
242
                commitDataFromFile, err := fileUtils.ReadFromCommitJsonFile(fileName)
3✔
243
                if err != nil {
4✔
244
                        return types.CommitFileData{}, err
1✔
245
                }
1✔
246

247
                log.Debug("GetCommittedDataForEpoch: Committed data from file: ", commitDataFromFile)
2✔
248
                if commitDataFromFile.Epoch != epoch {
3✔
249
                        log.Errorf("File %s doesn't contain latest committed data", fileName)
1✔
250
                        return types.CommitFileData{}, errors.New("commit data file doesn't contain latest committed data")
1✔
251
                }
1✔
252

253
                // Update global commit data struct since the file data is valid
254
                updateGlobalCommitDataStruct(types.CommitData{
1✔
255
                        Leaves:                 commitDataFromFile.Leaves,
1✔
256
                        SeqAllottedCollections: commitDataFromFile.SeqAllottedCollections,
1✔
257
                        AssignedCollections:    commitDataFromFile.AssignedCollections,
1✔
258
                }, commitDataFromFile.Commitment, epoch)
1✔
259
        }
260

261
        // Verify the final selected commit data
262
        log.Debugf("Verifying commit data for epoch %v...", epoch)
5✔
263
        isValid, err := VerifyCommitment(ctx, client, account, globalCommitDataStruct.Commitment)
5✔
264
        if err != nil {
5✔
NEW
265
                return types.CommitFileData{}, err
×
NEW
266
        }
×
267
        if !isValid {
6✔
268
                return types.CommitFileData{}, errors.New("commitment verification failed for selected commit data")
1✔
269
        }
1✔
270

271
        // If rogue mode is enabled, alter the commitment data
272
        if rogueData.IsRogue && utils.Contains(rogueData.RogueMode, "reveal") {
5✔
273
                log.Warn("YOU ARE REVEALING VALUES IN ROGUE MODE, THIS CAN INCUR PENALTIES!")
1✔
274
                globalCommitDataStruct.Leaves = generateRogueCommittedData(len(globalCommitDataStruct.Leaves))
1✔
275
                log.Debugf("Global Commit data struct in rogue mode: %+v", globalCommitDataStruct)
1✔
276
        }
1✔
277

278
        return globalCommitDataStruct, nil
4✔
279
}
280

281
func generateRogueCommittedData(length int) []*big.Int {
1✔
282
        var rogueCommittedData []*big.Int
1✔
283
        for i := 0; i < length; i++ {
3✔
284
                rogueCommittedData = append(rogueCommittedData, razorUtils.GetRogueRandomValue(10000000))
2✔
285
        }
2✔
286
        return rogueCommittedData
1✔
287
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc