Skip to content

Commit bf83e71

Browse files
omerfirmakrian
authored and
rian
committed
Implement Juno sequencing
Add a persistent mempool implementation wip wip wip core.BlockHash
1 parent efa8774 commit bf83e71

25 files changed

+7917
-34
lines changed

blockbuilder/genesis_state.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package blockbuilder
2+
3+
import (
4+
"github.com/NethermindEth/juno/core/felt"
5+
"github.com/NethermindEth/juno/validator"
6+
)
7+
8+
type GenesisConfig struct {
9+
ChainID string `json:"chain_id" validate:"required"`
10+
// Classes: Paths to 'class.json' files defining classes for the genesis block.
11+
Classes []string `json:"classes"`
12+
13+
// Contracts: Mapping of contract addresses to their initialisation data.
14+
// Class constructors called with "ConstructorArgs" will be deployed in the
15+
// genesis block. The contract address needs to match what the class generates.
16+
Contracts map[string]GenesisContractData `json:"contracts"`
17+
18+
// FunctionCalls: List of function calls whose resulting state
19+
// changes are applied to the genesis state. E.g. calling mint(amount,address)
20+
// on a token contract will result in the address having "amount" tokens.
21+
FunctionCalls []FunctionCall `json:"function_calls"`
22+
}
23+
24+
type GenesisContractData struct {
25+
ClassHash felt.Felt `json:"class_hash"`
26+
ConstructorArgs []felt.Felt `json:"constructor_args"`
27+
}
28+
type FunctionCall struct {
29+
ContractAddress felt.Felt `json:"contract_address"`
30+
EntryPointSelector felt.Felt `json:"entry_point_selector"`
31+
Calldata []felt.Felt `json:"calldata"`
32+
}
33+
34+
func (g *GenesisConfig) Validate() error {
35+
validate := validator.Validator()
36+
return validate.Struct(g)
37+
}

blockchain/blockchain.go

+109
Original file line numberDiff line numberDiff line change
@@ -1072,3 +1072,112 @@ func MakeStateDiffForEmptyBlock(bc Reader, blockNumber uint64) (*core.StateDiff,
10721072
}
10731073
return stateDiff, nil
10741074
}
1075+
1076+
type BlockSignFunc func(blockHash, stateDiffCommitment *felt.Felt) ([]*felt.Felt, error)
1077+
1078+
// Finalise will calculate the state commitment and block hash for the given pending block and append it to the
1079+
// blockchain
1080+
func (b *Blockchain) Finalise(pending *Pending, sign BlockSignFunc) error {
1081+
return b.database.Update(func(txn db.Transaction) error {
1082+
var err error
1083+
1084+
state := core.NewState(txn)
1085+
pending.StateUpdate.OldRoot, err = state.Root()
1086+
if err != nil {
1087+
return err
1088+
}
1089+
1090+
if h, hErr := chainHeight(txn); hErr == nil {
1091+
pending.Block.Number = h + 1
1092+
}
1093+
1094+
if err = state.Update(pending.Block.Number, pending.StateUpdate, pending.NewClasses); err != nil {
1095+
return err
1096+
}
1097+
1098+
pending.Block.GlobalStateRoot, err = state.Root()
1099+
if err != nil {
1100+
return err
1101+
}
1102+
pending.StateUpdate.NewRoot = pending.Block.GlobalStateRoot
1103+
1104+
var commitments *core.BlockCommitments
1105+
pending.Block.Hash, commitments, err = core.BlockHash(pending.Block, b.network)
1106+
if err != nil {
1107+
return err
1108+
}
1109+
pending.StateUpdate.BlockHash = pending.Block.Hash
1110+
1111+
pending.Block.Signatures = [][]*felt.Felt{}
1112+
var sig []*felt.Felt
1113+
sig, err = sign(pending.Block.Hash, pending.StateUpdate.StateDiff.Commitment())
1114+
if err != nil {
1115+
return err
1116+
}
1117+
if sig != nil {
1118+
pending.Block.Signatures = append(pending.Block.Signatures, sig)
1119+
}
1120+
1121+
if err = b.storeBlock(txn, pending.Block, commitments); err != nil {
1122+
return err
1123+
}
1124+
1125+
return storeStateUpdate(txn, pending.Block.Number, pending.StateUpdate)
1126+
})
1127+
}
1128+
1129+
func (b *Blockchain) storeBlock(txn db.Transaction, block *core.Block, blockCommitments *core.BlockCommitments) error {
1130+
if err := verifyBlock(txn, block); err != nil {
1131+
return err
1132+
}
1133+
1134+
if err := StoreBlockHeader(txn, block.Header); err != nil {
1135+
return err
1136+
}
1137+
1138+
for i, tx := range block.Transactions {
1139+
if err := storeTransactionAndReceipt(txn, block.Number, uint64(i), tx,
1140+
block.Receipts[i]); err != nil {
1141+
return err
1142+
}
1143+
}
1144+
1145+
if err := StoreBlockCommitments(txn, block.Number, blockCommitments); err != nil {
1146+
return err
1147+
}
1148+
1149+
if err := b.storeEmptyPending(txn, block.Header); err != nil {
1150+
return err
1151+
}
1152+
1153+
// Head of the blockchain is maintained as follows:
1154+
// [db.ChainHeight]() -> (BlockNumber)
1155+
heightBin := core.MarshalBlockNumber(block.Number)
1156+
return txn.Set(db.ChainHeight.Key(), heightBin)
1157+
}
1158+
1159+
func (b *Blockchain) StoreGenesis(diff *core.StateDiff, classes map[felt.Felt]core.Class) error {
1160+
receipts := make([]*core.TransactionReceipt, 0)
1161+
pendingGenesis := Pending{
1162+
Block: &core.Block{
1163+
Header: &core.Header{
1164+
ParentHash: &felt.Zero,
1165+
Number: 0,
1166+
SequencerAddress: &felt.Zero,
1167+
EventsBloom: core.EventsBloom(receipts),
1168+
GasPrice: &felt.Zero,
1169+
GasPriceSTRK: &felt.Zero,
1170+
},
1171+
Transactions: make([]core.Transaction, 0),
1172+
Receipts: receipts,
1173+
},
1174+
StateUpdate: &core.StateUpdate{
1175+
OldRoot: &felt.Zero,
1176+
StateDiff: diff,
1177+
},
1178+
NewClasses: classes,
1179+
}
1180+
return b.Finalise(&pendingGenesis, func(_, _ *felt.Felt) ([]*felt.Felt, error) {
1181+
return nil, nil
1182+
})
1183+
}

blockchain/pending.go

+124
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package blockchain
22

33
import (
4+
"errors"
5+
"fmt"
6+
47
"github.com/NethermindEth/juno/core"
58
"github.com/NethermindEth/juno/core/felt"
9+
"github.com/NethermindEth/juno/db"
610
)
711

812
type Pending struct {
@@ -65,3 +69,123 @@ func (p *PendingState) Class(classHash *felt.Felt) (*core.DeclaredClass, error)
6569

6670
return p.head.Class(classHash)
6771
}
72+
73+
func (p *PendingState) SetStorage(contractAddress, key, value *felt.Felt) error {
74+
if _, found := p.stateDiff.StorageDiffs[*contractAddress]; !found {
75+
p.stateDiff.StorageDiffs[*contractAddress] = make(map[felt.Felt]*felt.Felt)
76+
}
77+
p.stateDiff.StorageDiffs[*contractAddress][*key] = value.Clone()
78+
return nil
79+
}
80+
81+
func (p *PendingState) IncrementNonce(contractAddress *felt.Felt) error {
82+
currentNonce, err := p.ContractNonce(contractAddress)
83+
if err != nil {
84+
return fmt.Errorf("get contract nonce: %v", err)
85+
}
86+
newNonce := new(felt.Felt).SetUint64(1)
87+
p.stateDiff.Nonces[*contractAddress] = newNonce.Add(currentNonce, newNonce)
88+
return nil
89+
}
90+
91+
func (p *PendingState) SetClassHash(contractAddress, classHash *felt.Felt) error {
92+
if _, err := p.head.ContractClassHash(contractAddress); err != nil {
93+
if errors.Is(err, db.ErrKeyNotFound) {
94+
p.stateDiff.DeployedContracts[*contractAddress] = classHash.Clone()
95+
return nil
96+
}
97+
return fmt.Errorf("get latest class hash: %v", err)
98+
}
99+
p.stateDiff.ReplacedClasses[*contractAddress] = classHash.Clone()
100+
return nil
101+
}
102+
103+
func (p *PendingState) SetContractClass(classHash *felt.Felt, class core.Class) error {
104+
if _, err := p.Class(classHash); err == nil {
105+
return errors.New("class already declared")
106+
} else if !errors.Is(err, db.ErrKeyNotFound) {
107+
return fmt.Errorf("get class: %v", err)
108+
}
109+
110+
p.newClasses[*classHash] = class
111+
if class.Version() == 0 {
112+
p.stateDiff.DeclaredV0Classes = append(p.stateDiff.DeclaredV0Classes, classHash.Clone())
113+
} // assumption: SetCompiledClassHash will be called for Cairo1 contracts
114+
return nil
115+
}
116+
117+
func (p *PendingState) SetCompiledClassHash(classHash, compiledClassHash *felt.Felt) error {
118+
// assumption: SetContractClass was called for classHash and succeeded
119+
p.stateDiff.DeclaredV1Classes[*classHash] = compiledClassHash.Clone()
120+
return nil
121+
}
122+
123+
type PendingStateWriter struct {
124+
*PendingState
125+
}
126+
127+
func NewPendingStateWriter(stateDiff *core.StateDiff, newClasses map[felt.Felt]core.Class, head core.StateReader) *PendingStateWriter {
128+
return &PendingStateWriter{
129+
PendingState: &PendingState{
130+
stateDiff: stateDiff,
131+
newClasses: newClasses,
132+
head: head,
133+
},
134+
}
135+
}
136+
137+
func (p *PendingStateWriter) SetStorage(contractAddress, key, value *felt.Felt) error {
138+
if _, found := p.stateDiff.StorageDiffs[*contractAddress]; !found {
139+
p.stateDiff.StorageDiffs[*contractAddress] = make(map[felt.Felt]*felt.Felt)
140+
}
141+
p.stateDiff.StorageDiffs[*contractAddress][*key] = value.Clone()
142+
return nil
143+
}
144+
145+
func (p *PendingStateWriter) IncrementNonce(contractAddress *felt.Felt) error {
146+
currentNonce, err := p.ContractNonce(contractAddress)
147+
if err != nil {
148+
return fmt.Errorf("get contract nonce: %v", err)
149+
}
150+
newNonce := new(felt.Felt).SetUint64(1)
151+
p.stateDiff.Nonces[*contractAddress] = newNonce.Add(currentNonce, newNonce)
152+
return nil
153+
}
154+
155+
func (p *PendingStateWriter) SetClassHash(contractAddress, classHash *felt.Felt) error {
156+
if _, err := p.head.ContractClassHash(contractAddress); err != nil {
157+
if errors.Is(err, db.ErrKeyNotFound) {
158+
p.stateDiff.DeployedContracts[*contractAddress] = classHash.Clone()
159+
return nil
160+
}
161+
return fmt.Errorf("get latest class hash: %v", err)
162+
}
163+
p.stateDiff.ReplacedClasses[*contractAddress] = classHash.Clone()
164+
return nil
165+
}
166+
167+
func (p *PendingStateWriter) SetContractClass(classHash *felt.Felt, class core.Class) error {
168+
if _, err := p.Class(classHash); err == nil {
169+
return errors.New("class already declared")
170+
} else if !errors.Is(err, db.ErrKeyNotFound) {
171+
return fmt.Errorf("get class: %v", err)
172+
}
173+
174+
p.newClasses[*classHash] = class
175+
if class.Version() == 0 {
176+
p.stateDiff.DeclaredV0Classes = append(p.stateDiff.DeclaredV0Classes, classHash.Clone())
177+
} // assumption: SetCompiledClassHash will be called for Cairo1 contracts
178+
return nil
179+
}
180+
181+
func (p *PendingStateWriter) SetCompiledClassHash(classHash, compiledClassHash *felt.Felt) error {
182+
// assumption: SetContractClass was called for classHash and succeeded
183+
p.stateDiff.DeclaredV1Classes[*classHash] = compiledClassHash.Clone()
184+
return nil
185+
}
186+
187+
// StateDiffAndClasses returns the pending state's internal data. The returned objects will continue to be
188+
// read and modified by the pending state.
189+
func (p *PendingStateWriter) StateDiffAndClasses() (*core.StateDiff, map[felt.Felt]core.Class) {
190+
return p.stateDiff, p.newClasses
191+
}

0 commit comments

Comments
 (0)