-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmerkle_tree_test.go
113 lines (89 loc) · 4.88 KB
/
merkle_tree_test.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
package async_treasury
import (
"math/rand"
"strings"
"testing"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/code-payments/code-server/pkg/code/data/commitment"
"github.com/code-payments/code-server/pkg/code/data/intent"
)
// todo: Add tests for syncMerkleTree for treasury payments that land on the
// same block, which requires a mocked Solana client that doesn't currently
// exist.
func TestSyncMerkleTree(t *testing.T) {
env := setup(t, &testOverrides{})
// Nothing happens when there are no values to sync
require.NoError(t, env.worker.syncMerkleTree(env.ctx, env.treasuryPool))
env.assertEmptyMerkleTree(t)
// Empty merkle tree (no starting checkpoint, but an endpoint checkpoint exists)
allCommitmentRecords := env.simulateCommitments(t, 100, env.treasuryPool.GetMostRecentRoot(), commitment.StateReadyToOpen)
env.simulateMostRecentRoot(t, intent.StateConfirmed, allCommitmentRecords)
require.NoError(t, env.worker.syncMerkleTree(env.ctx, env.treasuryPool))
env.assertSyncedMerkleTree(t, allCommitmentRecords)
// Merkle tree with some leaves (both starting and ending checkpoint exist) over
// a few iterations
for i := 0; i < 10; i++ {
newCommitmentRecords := env.simulateCommitments(t, rand.Intn(100)+1, env.treasuryPool.GetMostRecentRoot(), commitment.StateReadyToOpen)
env.simulateMostRecentRoot(t, intent.StatePending, newCommitmentRecords)
// Intent isn't confirmed, so we error out
assert.Error(t, env.worker.syncMerkleTree(env.ctx, env.treasuryPool))
// Initial sync, which should yeild an updated merkle tree
env.simulateConfirmedIntent(t)
require.NoError(t, env.worker.syncMerkleTree(env.ctx, env.treasuryPool))
allCommitmentRecords = append(allCommitmentRecords, newCommitmentRecords...)
env.assertSyncedMerkleTree(t, allCommitmentRecords)
// Idempotency check where we shouldn't resync leaf values that have already
// been added to the merkle tree
require.NoError(t, env.worker.syncMerkleTree(env.ctx, env.treasuryPool))
env.assertSyncedMerkleTree(t, allCommitmentRecords)
}
}
func TestSafelyAddToMerkleTree(t *testing.T) {
env := setup(t, &testOverrides{})
commitmentRecords := env.simulateCommitments(t, 10, env.treasuryPool.GetMostRecentRoot(), commitment.StateReadyToOpen)
paymentRecords, err := env.data.GetPaymentHistory(env.ctx, env.treasuryPool.Vault)
require.NoError(t, err)
require.Len(t, paymentRecords, 10)
// No leaves to add
err = env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, nil)
assert.True(t, strings.Contains(err.Error(), "no treasury payments to add to the merkle tree"))
env.assertEmptyMerkleTree(t)
// Treasury pool most recent root isn't available to simulate adding leaves
err = env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, paymentRecords)
assert.True(t, strings.Contains(err.Error(), "calculated an incorrect recent root"))
env.assertEmptyMerkleTree(t)
env.simulateMostRecentRoot(t, intent.StateConfirmed, commitmentRecords)
// Payment records are out of order and won't lead to a successful simulation
firstPaymentRecord := paymentRecords[0]
paymentRecords[0] = paymentRecords[len(paymentRecords)-1]
paymentRecords[len(paymentRecords)-1] = firstPaymentRecord
err = env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, paymentRecords)
assert.True(t, strings.Contains(err.Error(), "calculated an incorrect recent root"))
env.assertEmptyMerkleTree(t)
paymentRecords, err = env.data.GetPaymentHistory(env.ctx, env.treasuryPool.Vault)
require.NoError(t, err)
require.Len(t, paymentRecords, 10)
// Subset of apyment records are missing and won't lead to a successful simulation
paymentRecords = append(paymentRecords[:3], paymentRecords[7:]...)
err = env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, paymentRecords)
assert.True(t, strings.Contains(err.Error(), "calculated an incorrect recent root"))
env.assertEmptyMerkleTree(t)
paymentRecords, err = env.data.GetPaymentHistory(env.ctx, env.treasuryPool.Vault)
require.NoError(t, err)
require.Len(t, paymentRecords, 10)
// Payment records are in the right order and will successfully lead to a correct simulation
require.NoError(t, env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, paymentRecords))
require.NoError(t, env.merkleTree.Refresh(env.ctx))
for i, commitmentRecord := range commitmentRecords {
expectedLeafValue, err := base58.Decode(commitmentRecord.Address)
require.NoError(t, err)
leafNode, err := env.merkleTree.GetLeafNodeByIndex(env.ctx, uint64(i))
require.NoError(t, err)
assert.EqualValues(t, expectedLeafValue, leafNode.LeafValue)
}
// Can't double add leaves
err = env.worker.safelyAddToMerkleTree(env.ctx, env.treasuryPool, env.merkleTree, paymentRecords)
assert.True(t, strings.Contains(err.Error(), "calculated an incorrect recent root"))
}