forked from crypto-org-chain/go-block-stm
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mock_block.go
169 lines (135 loc) · 3.66 KB
/
mock_block.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
158
159
160
161
162
163
164
165
166
167
168
169
package block_stm
import (
"encoding/binary"
"fmt"
"strings"
cryptorand "crypto/rand"
storetypes "cosmossdk.io/store/types"
"github.com/cometbft/cometbft/crypto/secp256k1"
)
var (
StoreKeyAuth = storetypes.NewKVStoreKey("acc")
StoreKeyBank = storetypes.NewKVStoreKey("bank")
)
type Tx func(MultiStore) error
type MockBlock struct {
Txs []Tx
Results []error
}
func NewMockBlock(txs []Tx) *MockBlock {
return &MockBlock{
Txs: txs,
Results: make([]error, len(txs)),
}
}
func (b *MockBlock) Size() int {
return len(b.Txs)
}
func (b *MockBlock) ExecuteTx(txn TxnIndex, store MultiStore) {
b.Results[txn] = b.Txs[txn](store)
}
// Simulated transaction logic for tests and benchmarks
// NoopTx verifies a signature and increases the nonce of the sender
func NoopTx(i int, sender string) Tx {
verifySig := genRandomSignature()
return func(store MultiStore) error {
verifySig()
return increaseNonce(i, sender, store.GetKVStore(StoreKeyAuth))
}
}
func BankTransferTx(i int, sender, receiver string, amount uint64) Tx {
base := NoopTx(i, sender)
return func(store MultiStore) error {
if err := base(store); err != nil {
return err
}
return bankTransfer(i, sender, receiver, amount, store.GetKVStore(StoreKeyBank))
}
}
func IterateTx(i int, sender, receiver string, amount uint64) Tx {
base := BankTransferTx(i, sender, receiver, amount)
return func(store MultiStore) error {
if err := base(store); err != nil {
return err
}
// find a nearby account, do a bank transfer
accStore := store.GetKVStore(StoreKeyAuth)
{
it := accStore.Iterator([]byte("nonce"+sender), nil)
defer it.Close()
var j int
for ; it.Valid(); it.Next() {
j++
if j > 5 {
recipient := strings.TrimPrefix(string(it.Key()), "nonce")
return bankTransfer(i, sender, recipient, amount, store.GetKVStore(StoreKeyBank))
}
}
}
{
it := accStore.ReverseIterator([]byte("nonce"), []byte("nonce"+sender))
defer it.Close()
var j int
for ; it.Valid(); it.Next() {
j++
if j > 5 {
recipient := strings.TrimPrefix(string(it.Key()), "nonce")
return bankTransfer(i, sender, recipient, amount, store.GetKVStore(StoreKeyBank))
}
}
}
return nil
}
}
func genRandomSignature() func() {
privKey := secp256k1.GenPrivKey()
signBytes := make([]byte, 1024)
if _, err := cryptorand.Read(signBytes); err != nil {
panic(err)
}
sig, _ := privKey.Sign(signBytes)
pubKey := privKey.PubKey()
return func() {
pubKey.VerifySignature(signBytes, sig)
}
}
func increaseNonce(i int, sender string, store storetypes.KVStore) error {
nonceKey := []byte("nonce" + sender)
var nonce uint64
v := store.Get(nonceKey)
if v != nil {
nonce = binary.BigEndian.Uint64(v)
}
var bz [8]byte
binary.BigEndian.PutUint64(bz[:], nonce+1)
store.Set(nonceKey, bz[:])
v = store.Get(nonceKey)
if binary.BigEndian.Uint64(v) != nonce+1 {
return fmt.Errorf("nonce not incremented: %d", binary.BigEndian.Uint64(v))
}
return nil
}
func bankTransfer(i int, sender, receiver string, amount uint64, store storetypes.KVStore) error {
senderKey := []byte("balance" + sender)
receiverKey := []byte("balance" + receiver)
var senderBalance, receiverBalance uint64
v := store.Get(senderKey)
if v != nil {
senderBalance = binary.BigEndian.Uint64(v)
}
v = store.Get(receiverKey)
if v != nil {
receiverBalance = binary.BigEndian.Uint64(v)
}
if senderBalance >= amount {
// avoid the failure
senderBalance -= amount
}
receiverBalance += amount
var bz1, bz2 [8]byte
binary.BigEndian.PutUint64(bz1[:], senderBalance)
store.Set(senderKey, bz1[:])
binary.BigEndian.PutUint64(bz2[:], receiverBalance)
store.Set(receiverKey, bz2[:])
return nil
}