github.com/igggame/nebulas-go@v2.1.0+incompatible/core/genesis.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package core
    20  
    21  import (
    22  	"fmt"
    23  	"io/ioutil"
    24  
    25  	"github.com/nebulasio/go-nebulas/crypto/keystore"
    26  
    27  	"github.com/gogo/protobuf/proto"
    28  	"github.com/nebulasio/go-nebulas/common/dag"
    29  	"github.com/nebulasio/go-nebulas/consensus/pb"
    30  	"github.com/nebulasio/go-nebulas/core/pb"
    31  	"github.com/nebulasio/go-nebulas/core/state"
    32  	"github.com/nebulasio/go-nebulas/util"
    33  	"github.com/nebulasio/go-nebulas/util/logging"
    34  	"github.com/sirupsen/logrus"
    35  )
    36  
    37  // Genesis Block Hash
    38  var (
    39  	GenesisHash        = make([]byte, BlockHashLength)
    40  	GenesisTimestamp   = int64(0)
    41  	GenesisCoinbase, _ = NewAddressFromPublicKey(make([]byte, PublicKeyDataLength))
    42  )
    43  
    44  // LoadGenesisConf load genesis conf for file
    45  func LoadGenesisConf(filePath string) (*corepb.Genesis, error) {
    46  	b, err := ioutil.ReadFile(filePath)
    47  	if err != nil {
    48  		logging.CLog().WithFields(logrus.Fields{
    49  			"err": err,
    50  		}).Error("Failed to read the genesis config file.")
    51  		return nil, err
    52  	}
    53  	content := string(b)
    54  
    55  	genesis := new(corepb.Genesis)
    56  	if err := proto.UnmarshalText(content, genesis); err != nil {
    57  		logging.CLog().WithFields(logrus.Fields{
    58  			"err": err,
    59  		}).Error("Failed to parse genesis file.")
    60  		return nil, err
    61  	}
    62  
    63  	return genesis, nil
    64  }
    65  
    66  // NewGenesisBlock create genesis @Block from file.
    67  func NewGenesisBlock(conf *corepb.Genesis, chain *BlockChain) (*Block, error) {
    68  	if conf == nil || chain == nil {
    69  		return nil, ErrNilArgument
    70  	}
    71  
    72  	worldState, err := state.NewWorldState(chain.ConsensusHandler(), chain.storage)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	genesisBlock := &Block{
    77  		header: &BlockHeader{
    78  			hash:          GenesisHash,
    79  			parentHash:    GenesisHash,
    80  			chainID:       conf.Meta.ChainId,
    81  			coinbase:      GenesisCoinbase,
    82  			timestamp:     GenesisTimestamp,
    83  			consensusRoot: &consensuspb.ConsensusRoot{},
    84  			alg:           keystore.SECP256K1,
    85  		},
    86  		transactions: make(Transactions, 0),
    87  		dependency:   dag.NewDag(),
    88  		worldState:   worldState,
    89  		txPool:       chain.txPool,
    90  		storage:      chain.storage,
    91  		eventEmitter: chain.eventEmitter,
    92  		nvm:          chain.nvm,
    93  		dip:          chain.dip,
    94  		height:       1,
    95  		sealed:       false,
    96  	}
    97  
    98  	consensusState, err := chain.ConsensusHandler().GenesisConsensusState(chain, conf)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	genesisBlock.worldState.SetConsensusState(consensusState)
   103  
   104  	if err := genesisBlock.Begin(); err != nil {
   105  		return nil, err
   106  	}
   107  	// add token distribution for genesis
   108  	for _, v := range conf.TokenDistribution {
   109  		addr, err := AddressParse(v.Address)
   110  		if err != nil {
   111  			logging.CLog().WithFields(logrus.Fields{
   112  				"address": v.Address,
   113  				"err":     err,
   114  			}).Error("Found invalid address in genesis token distribution.")
   115  			genesisBlock.RollBack()
   116  			return nil, err
   117  		}
   118  		acc, err := genesisBlock.worldState.GetOrCreateUserAccount(addr.address)
   119  		if err != nil {
   120  			genesisBlock.RollBack()
   121  			return nil, err
   122  		}
   123  		txsBalance, err := util.NewUint128FromString(v.Value)
   124  		if err != nil {
   125  			genesisBlock.RollBack()
   126  			return nil, err
   127  		}
   128  		err = acc.AddBalance(txsBalance)
   129  		if err != nil {
   130  			genesisBlock.RollBack()
   131  			return nil, err
   132  		}
   133  	}
   134  
   135  	// genesis transaction
   136  	declaration := fmt.Sprintf(
   137  		"%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n\n\n%s",
   138  		"Nebulas Manifesto",
   139  		"Yes! We Believe",
   140  		"We believe blockchains are a foundational innovation of the new world. At its essence, this innovation is about the decentralization of data. People will be empowered to claim ownership of their data through tokens, which will enable data to be valued and exchanged by everyone on the blockchain.",
   141  		"The blockchain community embodies the values of openness, collaboration, and transparency. An ecosystem created by blockchain believers is a voluntary association anchored by aligned incentives. We believe blockchain represents the social contract of the future, and that will lead to a civilization where cooperation, inclusion, and the interests of society converge.",
   142  		"Blockchains will make life more free, equitable and purposeful. As a nascent digital organism and economic system, blockchain is fertile ground for creative evolution. It will give rise to transformative ideas and breakthrough technologies. Now is a time of great opportunity, challenge and hope.",
   143  		"Do not ask what blockchain can do for you. Ask what you can do for blockchain.",
   144  		"This is the genesis of Nebulas.",
   145  
   146  		"星云宣言",
   147  		"Yes! We Believe",
   148  		"我们认为,区块链是奠基新世界的颠覆式创新,其本质是去中心化的数据确权。确权的数据承载于通证之上,对于“链上”数据的交互具有不可或缺的作用。",
   149  		"我们同时看到,真正的区块链社区秉持着开放、共享、透明的精神,逐步建立人类历史上前所未有的大规模协作关系。一个公正并有效的价值发现、激励以及持续进化机制所构成的生态系统,是这场大规模协作关系蓬勃发展的原生推动力,也是星云对于区块链的伟大使命。",
   150  		"我们始终坚信,区块链技术会帮助人们抵达更为自由、平等、美好的生活。区块链作为全新的生命体和经济体,意味着新的思想和技术,也蕴含着新的挑战、机遇和希望。面对无穷可能性的感召,不要问区块链能为你做什么,要问你能为区块链做什么。",
   151  		"星云正是为此而生。",
   152  
   153  		"by Nebulas (nebulas.io)",
   154  	)
   155  	declarationTx, err := NewTransaction(
   156  		chain.ChainID(),
   157  		GenesisCoinbase, GenesisCoinbase,
   158  		util.Uint128Zero(), 1,
   159  		TxPayloadBinaryType,
   160  		[]byte(declaration),
   161  		GenesisGasPrice,
   162  		MinGasCountPerTransaction,
   163  	)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	declarationTx.timestamp = 0
   168  	hash, err := declarationTx.calHash()
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	declarationTx.hash = hash
   173  	declarationTx.alg = keystore.SECP256K1
   174  	pbTx, err := declarationTx.ToProto()
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	txBytes, err := proto.Marshal(pbTx)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	genesisBlock.transactions = append(genesisBlock.transactions, declarationTx)
   183  	if err := genesisBlock.worldState.PutTx(declarationTx.hash, txBytes); err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	genesisBlock.Commit()
   188  
   189  	genesisBlock.header.stateRoot = genesisBlock.WorldState().AccountsRoot()
   190  	genesisBlock.header.txsRoot = genesisBlock.WorldState().TxsRoot()
   191  	genesisBlock.header.eventsRoot = genesisBlock.WorldState().EventsRoot()
   192  	genesisBlock.header.consensusRoot = genesisBlock.WorldState().ConsensusRoot()
   193  
   194  	genesisBlock.sealed = true
   195  
   196  	return genesisBlock, nil
   197  }
   198  
   199  // CheckGenesisBlock if a block is a genesis block
   200  func CheckGenesisBlock(block *Block) bool {
   201  	if block == nil {
   202  		return false
   203  	}
   204  	if block.Hash().Equals(GenesisHash) {
   205  		return true
   206  	}
   207  	return false
   208  }
   209  
   210  // CheckGenesisTransaction if a tx is a genesis transaction
   211  func CheckGenesisTransaction(tx *Transaction) bool {
   212  	if tx == nil {
   213  		return false
   214  	}
   215  	if tx.from.Equals(GenesisCoinbase) {
   216  		return true
   217  	}
   218  	return false
   219  }
   220  
   221  // DumpGenesis return the configuration of the genesis block in the storage
   222  func DumpGenesis(chain *BlockChain) (*corepb.Genesis, error) {
   223  	genesis, err := LoadBlockFromStorage(GenesisHash, chain)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	dynasty, err := genesis.worldState.Dynasty()
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	bootstrap := []string{}
   232  	for _, v := range dynasty {
   233  		addr, err := AddressParseFromBytes(v)
   234  		if err != nil {
   235  			return nil, err
   236  		}
   237  		bootstrap = append(bootstrap, addr.String())
   238  	}
   239  	distribution := []*corepb.GenesisTokenDistribution{}
   240  	accounts, err := genesis.worldState.Accounts()
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	for _, v := range accounts {
   245  		balance := v.Balance()
   246  		if v.Address().Equals(genesis.Coinbase().Bytes()) {
   247  			continue
   248  		}
   249  		addr, err := AddressParseFromBytes(v.Address())
   250  		if err != nil {
   251  			return nil, err
   252  		}
   253  		distribution = append(distribution, &corepb.GenesisTokenDistribution{
   254  			Address: addr.String(),
   255  			Value:   balance.String(),
   256  		})
   257  	}
   258  	return &corepb.Genesis{
   259  		Meta: &corepb.GenesisMeta{ChainId: genesis.ChainID()},
   260  		Consensus: &corepb.GenesisConsensus{
   261  			Dpos: &corepb.GenesisConsensusDpos{Dynasty: bootstrap},
   262  		},
   263  		TokenDistribution: distribution,
   264  	}, nil
   265  }
   266  
   267  //CheckGenesisConfByDB check mem and genesis.conf if equal return nil
   268  func CheckGenesisConfByDB(pGenesisDB *corepb.Genesis, pGenesis *corepb.Genesis) error {
   269  	//private function [Empty parameters are checked by the caller]
   270  	if pGenesisDB != nil {
   271  		if pGenesis.Meta.ChainId != pGenesisDB.Meta.ChainId {
   272  			return ErrGenesisNotEqualChainIDInDB
   273  		}
   274  
   275  		if len(pGenesis.Consensus.Dpos.Dynasty) != len(pGenesisDB.Consensus.Dpos.Dynasty) {
   276  			return ErrGenesisNotEqualDynastyLenInDB
   277  		}
   278  
   279  		if len(pGenesis.TokenDistribution) != len(pGenesisDB.TokenDistribution) {
   280  			return ErrGenesisNotEqualTokenLenInDB
   281  		}
   282  
   283  		// check dpos equal
   284  		for _, confDposAddr := range pGenesis.Consensus.Dpos.Dynasty {
   285  			contains := false
   286  			for _, dposAddr := range pGenesisDB.Consensus.Dpos.Dynasty {
   287  				if dposAddr == confDposAddr {
   288  					contains = true
   289  					break
   290  				}
   291  			}
   292  			if !contains {
   293  				return ErrGenesisNotEqualDynastyInDB
   294  			}
   295  
   296  		}
   297  
   298  		// check distribution equal
   299  		for _, confDistribution := range pGenesis.TokenDistribution {
   300  			contains := false
   301  			for _, distribution := range pGenesisDB.TokenDistribution {
   302  				if distribution.Address == confDistribution.Address &&
   303  					distribution.Value == confDistribution.Value {
   304  					contains = true
   305  					break
   306  				}
   307  			}
   308  			if !contains {
   309  				return ErrGenesisNotEqualTokenInDB
   310  			}
   311  		}
   312  	}
   313  	return nil
   314  }