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  }