-
Notifications
You must be signed in to change notification settings - Fork 158
/
block.go
224 lines (193 loc) · 6.94 KB
/
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package core
import (
"encoding/binary"
"errors"
"fmt"
"github.com/NethermindEth/juno/core/crypto"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/utils"
"github.com/bits-and-blooms/bloom/v3"
"github.com/sourcegraph/conc"
)
type Header struct {
// The hash of this block
Hash *felt.Felt
// The hash of this block’s parent
ParentHash *felt.Felt
// The number (height) of this block
Number uint64
// The state commitment after this block
GlobalStateRoot *felt.Felt
// The Starknet address of the sequencer who created this block
SequencerAddress *felt.Felt
// The amount Transactions and Receipts stored in this block
TransactionCount uint64
// The amount of events stored in transaction receipts
EventCount uint64
// The time the sequencer created this block before executing transactions
Timestamp uint64
// The version of the Starknet protocol used when creating this block
ProtocolVersion string
// Bloom filter on the events emitted this block
EventsBloom *bloom.BloomFilter
// Amount of WEI charged per Gas spent
GasPrice *felt.Felt
// Sequencer signatures
Signatures [][]*felt.Felt
// Amount of STRK charged per Gas spent
GasPriceSTRK *felt.Felt
// The mode of the L1 data availability
L1DAMode L1DAMode
// The gas price for L1 data availability
L1DataGasPrice *GasPrice
}
type L1DAMode uint
const (
Calldata L1DAMode = iota
Blob
)
type GasPrice struct {
PriceInWei *felt.Felt
PriceInFri *felt.Felt
}
type Block struct {
*Header
Transactions []Transaction
Receipts []*TransactionReceipt
}
type BlockCommitments struct {
TransactionCommitment *felt.Felt
EventCommitment *felt.Felt
}
// VerifyBlockHash verifies the block hash. Due to bugs in Starknet alpha, not all blocks have
// verifiable hashes.
func VerifyBlockHash(b *Block, network *utils.Network) (*BlockCommitments, error) {
if len(b.Transactions) != len(b.Receipts) {
return nil, fmt.Errorf("len of transactions: %v do not match len of receipts: %v",
len(b.Transactions), len(b.Receipts))
}
for i, tx := range b.Transactions {
if !tx.Hash().Equal(b.Receipts[i].TransactionHash) {
return nil, fmt.Errorf(
"transaction hash (%v) at index: %v does not match receipt's hash (%v)",
tx.Hash().String(), i, b.Receipts[i].TransactionHash)
}
}
metaInfo := network.BlockHashMetaInfo
unverifiableRange := metaInfo.UnverifiableRange
skipVerification := unverifiableRange != nil && b.Number >= unverifiableRange[0] && b.Number <= unverifiableRange[1] //nolint:gocritic
if !skipVerification {
if err := VerifyTransactions(b.Transactions, network, b.ProtocolVersion); err != nil {
return nil, err
}
}
fallbackSeqAddresses := []*felt.Felt{&felt.Zero}
if metaInfo.FallBackSequencerAddress != nil {
fallbackSeqAddresses = append(fallbackSeqAddresses, metaInfo.FallBackSequencerAddress)
}
for _, fallbackSeq := range fallbackSeqAddresses {
var overrideSeq *felt.Felt
if b.SequencerAddress == nil {
overrideSeq = fallbackSeq
}
hash, commitments, err := blockHash(b, network, overrideSeq)
if err != nil {
return nil, err
}
if hash.Equal(b.Hash) {
return commitments, nil
} else if skipVerification {
// Check if the block number is in the unverifiable range
// If so, return success
return commitments, nil
}
}
return nil, errors.New("can not verify hash in block header")
}
// BlockHash assumes block.SequencerAddress is not nil as this is called with post v0.12.0
// and by then issues with unverifiable block hash were resolved.
// In future, this may no longer be required.
func BlockHash(b *Block) (*felt.Felt, error) {
if b.SequencerAddress == nil {
return nil, errors.New("block.SequencerAddress is nil")
}
h, _, err := post07Hash(b, nil)
return h, err
}
// blockHash computes the block hash, with option to override sequence address
func blockHash(b *Block, network *utils.Network, overrideSeqAddr *felt.Felt) (*felt.Felt, *BlockCommitments, error) {
metaInfo := network.BlockHashMetaInfo
if b.Number < metaInfo.First07Block {
return pre07Hash(b, network.L2ChainIDFelt())
}
return post07Hash(b, overrideSeqAddr)
}
// pre07Hash computes the block hash for blocks generated before Cairo 0.7.0
func pre07Hash(b *Block, chain *felt.Felt) (*felt.Felt, *BlockCommitments, error) {
txCommitment, err := transactionCommitment(b.Transactions, b.Header.ProtocolVersion)
if err != nil {
return nil, nil, err
}
return crypto.PedersenArray(
new(felt.Felt).SetUint64(b.Number), // block number
b.GlobalStateRoot, // global state root
&felt.Zero, // reserved: sequencer address
&felt.Zero, // reserved: block timestamp
new(felt.Felt).SetUint64(b.TransactionCount), // number of transactions
txCommitment, // transaction commitment
&felt.Zero, // reserved: number of events
&felt.Zero, // reserved: event commitment
&felt.Zero, // reserved: protocol version
&felt.Zero, // reserved: extra data
chain, // extra data: chain id
b.ParentHash, // parent hash
), &BlockCommitments{TransactionCommitment: txCommitment}, nil
}
// post07Hash computes the block hash for blocks generated after Cairo 0.7.0
func post07Hash(b *Block, overrideSeqAddr *felt.Felt) (*felt.Felt, *BlockCommitments, error) {
seqAddr := b.SequencerAddress
if overrideSeqAddr != nil {
seqAddr = overrideSeqAddr
}
wg := conc.NewWaitGroup()
var txCommitment, eCommitment *felt.Felt
var tErr, eErr error
wg.Go(func() {
txCommitment, tErr = transactionCommitment(b.Transactions, b.Header.ProtocolVersion)
})
wg.Go(func() {
eCommitment, eErr = eventCommitment(b.Receipts)
})
wg.Wait()
if tErr != nil {
return nil, nil, tErr
}
if eErr != nil {
return nil, nil, eErr
}
// Unlike the pre07Hash computation, we exclude the chain
// id and replace the zero felt with the actual values for:
// - sequencer address
// - block timestamp
// - number of events
// - event commitment
return crypto.PedersenArray(
new(felt.Felt).SetUint64(b.Number), // block number
b.GlobalStateRoot, // global state root
seqAddr, // sequencer address
new(felt.Felt).SetUint64(b.Timestamp), // block timestamp
new(felt.Felt).SetUint64(b.TransactionCount), // number of transactions
txCommitment, // transaction commitment
new(felt.Felt).SetUint64(b.EventCount), // number of events
eCommitment, // event commitment
&felt.Zero, // reserved: protocol version
&felt.Zero, // reserved: extra data
b.ParentHash, // parent block hash
), &BlockCommitments{TransactionCommitment: txCommitment, EventCommitment: eCommitment}, nil
}
func MarshalBlockNumber(blockNumber uint64) []byte {
const blockNumberSize = 8
numBytes := make([]byte, blockNumberSize)
binary.BigEndian.PutUint64(numBytes, blockNumber)
return numBytes
}