11import Blockchain
2+ import Codec
23import Foundation
34import Utils
45
@@ -57,41 +58,50 @@ extension Genesis {
5758 config = genesis. config!
5859 }
5960 let configRef = Ref ( config)
60- let ( state, block) = try State . devGenesis ( config: configRef)
61+ let state = genesis. state. asRef ( )
62+ let block = genesis. block. asRef ( )
63+
6164 return ( state, block, configRef)
6265 }
6366 }
6467
6568 private func validate( _ genesis: GenesisData ) throws {
6669 // Validate required fields
6770 if genesis. name. isEmpty {
68- throw GenesisError . invalidFormat ( " Invalid or missing 'name'" )
71+ throw GenesisError . invalidFormat ( " Missing 'name'" )
6972 }
7073 if genesis. id. isEmpty {
71- throw GenesisError . invalidFormat ( " Invalid or missing 'id' " )
72- }
73- if genesis. bootnodes. isEmpty {
74- throw GenesisError . invalidFormat ( " Invalid or missing 'bootnodes' " )
74+ throw GenesisError . invalidFormat ( " Missing 'id' " )
7575 }
76- if genesis. state . isEmpty {
77- throw GenesisError . invalidFormat ( " Invalid or missing 'state' " )
76+ if genesis. preset == nil , genesis . config == nil {
77+ throw GenesisError . invalidFormat ( " One of 'preset' or 'config' is required " )
7878 }
7979 }
8080
81- func readAndValidateGenesis ( from filePath: String ) throws -> GenesisData {
81+ private func readFile ( from filePath: String ) throws -> Data {
8282 do {
8383 let fileContents = try String ( contentsOfFile: filePath, encoding: . utf8)
84- let data = fileContents. data ( using: . utf8) !
85- let decoder = JSONDecoder ( )
86- let genesis = try decoder. decode ( GenesisData . self, from: data)
87- try validate ( genesis)
88- return genesis
89- } catch let error as GenesisError {
90- throw error
84+ return fileContents. data ( using: . utf8) !
9185 } catch {
9286 throw GenesisError . fileReadError ( error)
9387 }
9488 }
89+
90+ private func parseGenesis( from data: Data ) throws -> GenesisData {
91+ let decoder = JSONDecoder ( )
92+ if let genesisData = try ? decoder. decode ( GenesisData . self, from: data) {
93+ return genesisData
94+ }
95+ let genesisData = try decoder. decode ( GenesisDataBinary . self, from: data)
96+ return try genesisData. toGenesisData ( )
97+ }
98+
99+ func readAndValidateGenesis( from filePath: String ) throws -> GenesisData {
100+ let data = try readFile ( from: filePath)
101+ let genesis = try parseGenesis ( from: data)
102+ try validate ( genesis)
103+ return genesis
104+ }
95105}
96106
97107extension KeyedDecodingContainer {
@@ -107,27 +117,86 @@ extension KeyedDecodingContainer {
107117 }
108118}
109119
110- struct GenesisData : Codable {
111- var name : String
112- var id : String
113- var bootnodes : [ String ]
114- var preset : GenesisPreset ?
115- var config : ProtocolConfig ?
116- // TODO: check & deal with state
117- var state : String
118-
119- // ensure one of preset or config is present
120- init ( from decoder: Decoder ) throws {
121- let container = try decoder. container ( keyedBy: CodingKeys . self)
122- name = try container. decode ( String . self, forKey: . name)
123- id = try container. decode ( String . self, forKey: . id)
124- bootnodes = try container. decode ( [ String ] . self, forKey: . bootnodes)
125- preset = try container. decodeIfPresent ( GenesisPreset . self, forKey: . preset)
126- if preset == nil {
127- config = try container. decode ( ProtocolConfig . self, forKey: . config, required: true )
128- } else {
129- config = try container. decodeIfPresent ( ProtocolConfig . self, forKey: . config, required: false )
120+ private func getConfig( preset: GenesisPreset ? , config: ProtocolConfig ? ) throws -> ProtocolConfig {
121+ if let preset {
122+ let ret = preset. config. value
123+ if let genesisConfig = config {
124+ return ret. merged ( with: genesisConfig)
130125 }
131- state = try container. decode ( String . self, forKey: . state)
126+ return ret
127+ }
128+ if let config {
129+ return config
130+ }
131+ throw GenesisError . invalidFormat ( " One of 'preset' or 'config' is required " )
132+ }
133+
134+ public struct GenesisData : Codable {
135+ public var name : String
136+ public var id : String
137+ public var bootnodes : [ String ]
138+ public var preset : GenesisPreset ?
139+ public var config : ProtocolConfig ?
140+ public var block : Block
141+ public var state : State
142+
143+ public init (
144+ name: String ,
145+ id: String ,
146+ bootnodes: [ String ] ,
147+ preset: GenesisPreset ? ,
148+ config: ProtocolConfig ? ,
149+ block: Block ,
150+ state: State
151+ ) {
152+ self . name = name
153+ self . id = id
154+ self . bootnodes = bootnodes
155+ self . preset = preset
156+ self . config = config
157+ self . block = block
158+ self . state = state
159+ }
160+ }
161+
162+ public struct GenesisDataBinary : Codable {
163+ public var name : String
164+ public var id : String
165+ public var bootnodes : [ String ]
166+ public var preset : GenesisPreset ?
167+ public var config : ProtocolConfig ?
168+ public var block : Data
169+ public var state : Data
170+
171+ public init (
172+ name: String ,
173+ id: String ,
174+ bootnodes: [ String ] ,
175+ preset: GenesisPreset ? ,
176+ config: ProtocolConfig ? ,
177+ block: Data ,
178+ state: Data
179+ ) {
180+ self . name = name
181+ self . id = id
182+ self . bootnodes = bootnodes
183+ self . preset = preset
184+ self . config = config
185+ self . block = block
186+ self . state = state
187+ }
188+
189+ public func toGenesisData( ) throws -> GenesisData {
190+ let block = try JamDecoder ( data: block, config: config) . decode ( Block . self)
191+ let state = try JamDecoder ( data: state, config: config) . decode ( State . self)
192+ return GenesisData (
193+ name: name,
194+ id: id,
195+ bootnodes: bootnodes,
196+ preset: preset,
197+ config: config,
198+ block: block,
199+ state: state
200+ )
132201 }
133202}
0 commit comments