github.com/aergoio/aergo@v1.3.1/types/genesis.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "math" 10 "math/big" 11 "strings" 12 "time" 13 14 "github.com/aergoio/aergo/internal/common" 15 ) 16 17 const ( 18 blockVersionNil = math.MinInt32 19 devChainMagic = "dev.chain" 20 ) 21 22 var ( 23 nilChainID = ChainID{ 24 Version: 0, 25 Magic: "", 26 PublicNet: false, 27 MainNet: false, 28 Consensus: "", 29 } 30 31 defaultChainID = ChainID{ 32 Version: 0, 33 Magic: devChainMagic, 34 PublicNet: false, 35 MainNet: false, 36 Consensus: "sbp", 37 } 38 ) 39 40 const ( 41 cidMarshal = iota 42 cidUnmarshal 43 ) 44 45 type errCidCodec struct { 46 codec int 47 field string 48 err error 49 } 50 51 func (e errCidCodec) Error() string { 52 kind := "unmarshal" 53 if e.codec == cidMarshal { 54 kind = "marshal" 55 } 56 return fmt.Sprintf("failed to %s %s - %s", kind, e.field, e.err.Error()) 57 } 58 59 // ChainID represents the identity of the chain. 60 type ChainID struct { 61 Version int32 `json:"-"` 62 PublicNet bool `json:"public"` 63 MainNet bool `json:"mainnet"` 64 Magic string `json:"magic"` 65 Consensus string `json:"consensus"` 66 } 67 68 // NewChainID returns a new ChainID initialized as nilChainID. 69 func NewChainID() *ChainID { 70 nilCID := nilChainID 71 72 return &nilCID 73 } 74 75 // Bytes returns the binary representation of cid. 76 func (cid *ChainID) Bytes() ([]byte, error) { 77 var w bytes.Buffer 78 79 // warning: when any field added to ChainID, the corresponding 80 // serialization code must be written here. 81 if err := binary.Write(&w, binary.LittleEndian, cid.Version); err != nil { 82 return nil, errCidCodec{ 83 codec: cidMarshal, 84 field: "version", 85 err: err, 86 } 87 } 88 if err := binary.Write(&w, binary.LittleEndian, cid.PublicNet); err != nil { 89 return nil, errCidCodec{ 90 codec: cidMarshal, 91 field: "publicnet", 92 err: err, 93 } 94 } 95 if err := binary.Write(&w, binary.LittleEndian, cid.MainNet); err != nil { 96 return nil, errCidCodec{ 97 codec: cidMarshal, 98 field: "mainnet", 99 err: err, 100 } 101 } 102 103 others := fmt.Sprintf("%s/%s", cid.Magic, cid.Consensus) 104 if err := binary.Write(&w, binary.LittleEndian, []byte(others)); err != nil { 105 return nil, errCidCodec{ 106 codec: cidMarshal, 107 field: "magic/consensus", 108 err: err, 109 } 110 } 111 112 return w.Bytes(), nil 113 } 114 115 // Read deserialize data as a ChainID. 116 func (cid *ChainID) Read(data []byte) error { 117 r := bytes.NewBuffer(data) 118 119 // warning: when any field added to ChainID, the corresponding 120 // deserialization code must be written here. 121 if err := binary.Read(r, binary.LittleEndian, &cid.Version); err != nil { 122 return errCidCodec{ 123 codec: cidUnmarshal, 124 field: "version", 125 err: err, 126 } 127 } 128 if err := binary.Read(r, binary.LittleEndian, &cid.PublicNet); err != nil { 129 return errCidCodec{ 130 codec: cidUnmarshal, 131 field: "publicnet", 132 err: err, 133 } 134 } 135 if err := binary.Read(r, binary.LittleEndian, &cid.MainNet); err != nil { 136 return errCidCodec{ 137 codec: cidUnmarshal, 138 field: "mainnet", 139 err: err, 140 } 141 } 142 mc := strings.Split(string(r.Bytes()), "/") 143 if len(mc) != 2 { 144 return errCidCodec{ 145 codec: cidUnmarshal, 146 field: "magic/consensus", 147 err: fmt.Errorf("wrong number of fields: %s", mc), 148 } 149 } 150 cid.Magic, cid.Consensus = mc[0], mc[1] 151 152 return nil 153 } 154 155 // AsDefault set *cid to the default chaind id (cid must be a valid pointer). 156 func (cid *ChainID) AsDefault() { 157 *cid = defaultChainID 158 } 159 160 // Equals reports wheter cid equals rhs or not. 161 func (cid *ChainID) Equals(rhs *ChainID) bool { 162 var ( 163 lVal, rVal []byte 164 err error 165 ) 166 167 if lVal, err = cid.Bytes(); err != nil { 168 return false 169 } 170 if rVal, err = rhs.Bytes(); err != nil { 171 return false 172 } 173 174 return bytes.Compare(lVal, rVal) == 0 175 } 176 177 // ToJSON returns a JSON encoded string of cid. 178 func (cid ChainID) ToJSON() string { 179 if b, err := json.Marshal(cid); err == nil { 180 return string(b) 181 } 182 return "" 183 } 184 185 type EnterpriseBP struct { 186 Name string `json:"name"` 187 // multiaddress format with ip or dns with port e.g. /ip4/123.45.67.89/tcp/7846 188 Address string `json:"address"` 189 PeerID string `json:"peerid"` 190 } 191 192 // Genesis represents genesis block 193 type Genesis struct { 194 ID ChainID `json:"chain_id,omitempty"` 195 Timestamp int64 `json:"timestamp,omitempty"` 196 Balance map[string]string `json:"balance"` 197 BPs []string `json:"bps"` 198 EnterpriseBPs []EnterpriseBP `json:"enterprise_bps,omitempty"` 199 200 // followings are for internal use only 201 totalBalance *big.Int 202 block *Block 203 } 204 205 // Block returns Block corresponding to g. If g.block == nil, it genreates a 206 // genesis block before it returns. 207 func (g *Genesis) Validate() error { 208 _, err := g.ChainID() 209 if err != nil { 210 return err 211 } 212 //TODO check BP count 213 return nil 214 } 215 216 // Block returns Block corresponding to g. 217 func (g *Genesis) Block() *Block { 218 if g.block == nil { 219 g.SetBlock(NewBlock(nil, nil, nil, nil, nil, g.Timestamp)) 220 if id, err := g.ID.Bytes(); err == nil { 221 g.block.SetChainID(id) 222 } 223 } 224 return g.block 225 } 226 227 // AddBalance adds bal to g.totalBalance. 228 func (g *Genesis) AddBalance(bal *big.Int) { 229 if g.totalBalance == nil { 230 g.totalBalance = big.NewInt(0) 231 } 232 g.totalBalance.Add(g.totalBalance, bal) 233 } 234 235 // TotalBalance returns the total initial balance of the chain. 236 func (g *Genesis) TotalBalance() *big.Int { 237 return g.totalBalance 238 } 239 240 // SetTotalBalance sets g.totalBalance to v if g.totalBlance has no valid 241 // value (nil). 242 func (g *Genesis) SetTotalBalance(v []byte) { 243 if g.totalBalance == nil { 244 g.totalBalance = big.NewInt(0).SetBytes(v) 245 } 246 } 247 248 // SetBlock sets g.block to block if g.block == nil. 249 func (g *Genesis) SetBlock(block *Block) { 250 if g.block == nil { 251 g.block = block 252 } 253 } 254 255 // ChainID returns the binary representation of g.ID. 256 func (g *Genesis) ChainID() ([]byte, error) { 257 return g.ID.Bytes() 258 } 259 260 // Bytes returns byte-encoded BPs from g. 261 func (g Genesis) Bytes() []byte { 262 // Omit the Balance to reduce the resulting data size. 263 g.Balance = nil 264 if b, err := common.GobEncode(g); err == nil { 265 return b 266 } 267 return nil 268 } 269 270 // ConsensusType retruns g.ID.ConsensusType. 271 func (g Genesis) ConsensusType() string { 272 return g.ID.Consensus 273 } 274 275 // PublicNet reports whether g corresponds to PublicNet. 276 func (g Genesis) PublicNet() bool { 277 return g.ID.PublicNet 278 } 279 280 func (g Genesis) IsAergoPublicChain() bool { 281 282 testNetCid := GetTestNetGenesis().ID 283 mainNetCid := GetMainNetGenesis().ID 284 if testNetCid.Equals(&g.ID) || mainNetCid.Equals(&g.ID) { 285 return true 286 } 287 return false 288 } 289 290 func (g Genesis) HasDevChainID() bool { 291 if g.ID.Magic == devChainMagic { 292 return true 293 } 294 return false 295 } 296 297 func (g Genesis) HasPrivateChainID() bool { 298 if g.IsAergoPublicChain() || g.HasDevChainID() { 299 return false 300 } 301 return true 302 } 303 304 // GetDefaultGenesis returns default genesis structure 305 func GetDefaultGenesis() *Genesis { 306 return &Genesis{ 307 ID: defaultChainID, 308 Timestamp: time.Now().UnixNano(), 309 block: nil, 310 } //TODO embed MAINNET genesis block 311 } 312 313 func GetMainNetGenesis() *Genesis { 314 if bs, err := hex.DecodeString(MainNetGenesis); err == nil { 315 var g Genesis 316 if err := json.Unmarshal(bs, &g); err == nil { 317 return &g 318 } 319 } 320 return nil 321 } 322 func GetTestNetGenesis() *Genesis { 323 if bs, err := hex.DecodeString(TestNetGenesis); err == nil { 324 var g Genesis 325 if err := json.Unmarshal(bs, &g); err == nil { 326 return &g 327 } 328 } 329 return nil 330 } 331 332 // GetTestGenesis returns Gensis object for a unit test. 333 func GetTestGenesis() *Genesis { 334 genesis := &Genesis{ 335 ID: ChainID{ 336 Version: 0, 337 Magic: devChainMagic, 338 PublicNet: true, 339 MainNet: false, 340 Consensus: "sbp", 341 }, 342 Timestamp: time.Now().UnixNano(), 343 block: nil, 344 } //TODO embed MAINNET genesis block 345 346 genesis.Block() 347 348 return genesis 349 } 350 351 // GetGenesisFromBytes decodes & return Genesis from b. 352 func GetGenesisFromBytes(b []byte) *Genesis { 353 g := &Genesis{} 354 if err := common.GobDecode(b, g); err == nil { 355 return g 356 } 357 return nil 358 }