You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
5.6 KiB
151 lines
5.6 KiB
package node
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"math/big"
|
|
"math/rand"
|
|
"strings"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/harmony-one/harmony/common/denominations"
|
|
"github.com/harmony-one/harmony/core"
|
|
"github.com/harmony-one/harmony/core/rawdb"
|
|
"github.com/harmony-one/harmony/core/types"
|
|
"github.com/harmony-one/harmony/internal/ctxerror"
|
|
"github.com/harmony-one/harmony/internal/utils"
|
|
"github.com/harmony-one/harmony/internal/utils/contract"
|
|
)
|
|
|
|
const (
|
|
// FakeAddressNumber is the number of fake address.
|
|
FakeAddressNumber = 100
|
|
// TotalInitFund is the initial total fund for the contract deployer.
|
|
TotalInitFund = 1000000100
|
|
// InitFreeFundInEther is the initial fund for sample accounts.
|
|
InitFreeFundInEther = 100
|
|
)
|
|
|
|
// genesisInitializer is a shardchain.DBInitializer adapter.
|
|
type genesisInitializer struct {
|
|
node *Node
|
|
}
|
|
|
|
// InitChainDB sets up a new genesis block in the database for the given shard.
|
|
func (gi *genesisInitializer) InitChainDB(db ethdb.Database, shardID uint32) error {
|
|
shardState := core.GetInitShardState()
|
|
if shardID != 0 {
|
|
// store only the local shard
|
|
c := shardState.FindCommitteeByID(shardID)
|
|
if c == nil {
|
|
return errors.New("cannot find local shard in genesis")
|
|
}
|
|
shardState = types.ShardState{*c}
|
|
}
|
|
if err := rawdb.WriteShardState(db, common.Big0, shardState); err != nil {
|
|
return ctxerror.New("cannot store epoch shard state").WithCause(err)
|
|
}
|
|
if err := gi.node.SetupGenesisBlock(db, shardID); err != nil {
|
|
return ctxerror.New("cannot setup genesis block").WithCause(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetupGenesisBlock sets up a genesis blockchain.
|
|
func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32) error {
|
|
utils.GetLogger().Info("setting up a brand new chain database",
|
|
"shardID", shardID)
|
|
if shardID == node.Consensus.ShardID {
|
|
node.isFirstTime = true
|
|
}
|
|
|
|
// Initialize genesis block and blockchain
|
|
// Tests account for txgen to use
|
|
|
|
genesisAlloc := node.CreateGenesisAllocWithTestingAddresses(FakeAddressNumber)
|
|
|
|
// Smart contract deployer account used to deploy protocol-level smart contract
|
|
contractDeployerKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time"))
|
|
contractDeployerAddress := crypto.PubkeyToAddress(contractDeployerKey.PublicKey)
|
|
contractDeployerFunds := big.NewInt(TotalInitFund)
|
|
contractDeployerFunds = contractDeployerFunds.Mul(contractDeployerFunds, big.NewInt(denominations.One))
|
|
genesisAlloc[contractDeployerAddress] = core.GenesisAccount{Balance: contractDeployerFunds}
|
|
node.ContractDeployerKey = contractDeployerKey
|
|
|
|
// Add puzzle fund
|
|
puzzleFunds := big.NewInt(TotalInitFund)
|
|
puzzleFunds = puzzleFunds.Mul(puzzleFunds, big.NewInt(denominations.One))
|
|
genesisAlloc[common.HexToAddress(contract.PuzzleAccounts[0].Address)] = core.GenesisAccount{Balance: puzzleFunds}
|
|
|
|
if shardID == 0 {
|
|
// Accounts used by validator/nodes to stake and participate in the network.
|
|
AddNodeAddressesToGenesisAlloc(genesisAlloc)
|
|
}
|
|
|
|
// TODO: create separate chain config instead of using the same pointer reference
|
|
chainConfig := *params.TestChainConfig
|
|
chainConfig.ChainID = big.NewInt(int64(shardID)) // Use ChainID as piggybacked ShardID
|
|
gspec := core.Genesis{
|
|
Config: &chainConfig,
|
|
Alloc: genesisAlloc,
|
|
ShardID: shardID,
|
|
}
|
|
|
|
// Store genesis block into db.
|
|
_, err := gspec.Commit(db)
|
|
|
|
return err
|
|
}
|
|
|
|
// CreateTestBankKeys deterministically generates testing addresses.
|
|
func CreateTestBankKeys(numAddresses int) (keys []*ecdsa.PrivateKey, err error) {
|
|
rand.Seed(0)
|
|
bytes := make([]byte, 1000000)
|
|
for i := range bytes {
|
|
bytes[i] = byte(rand.Intn(100))
|
|
}
|
|
reader := strings.NewReader(string(bytes))
|
|
for i := 0; i < numAddresses; i++ {
|
|
key, err := ecdsa.GenerateKey(crypto.S256(), reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
keys = append(keys, key)
|
|
}
|
|
return keys, nil
|
|
}
|
|
|
|
// CreateGenesisAllocWithTestingAddresses create the genesis block allocation that contains deterministically
|
|
// generated testing addresses with tokens. This is mostly used for generated simulated transactions in txgen.
|
|
// TODO: Remove it later when moving to production.
|
|
func (node *Node) CreateGenesisAllocWithTestingAddresses(numAddress int) core.GenesisAlloc {
|
|
genesisAloc := make(core.GenesisAlloc)
|
|
for _, testBankKey := range node.TestBankKeys {
|
|
testBankAddress := crypto.PubkeyToAddress(testBankKey.PublicKey)
|
|
testBankFunds := big.NewInt(InitFreeFundInEther)
|
|
testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(denominations.One))
|
|
genesisAloc[testBankAddress] = core.GenesisAccount{Balance: testBankFunds}
|
|
}
|
|
return genesisAloc
|
|
}
|
|
|
|
// AddNodeAddressesToGenesisAlloc adds to the genesis block allocation the accounts used for network validators/nodes,
|
|
// including the account used by the nodes of the initial beacon chain and later new nodes.
|
|
func AddNodeAddressesToGenesisAlloc(genesisAlloc core.GenesisAlloc) {
|
|
for _, account := range contract.GenesisAccounts {
|
|
testBankFunds := big.NewInt(InitFreeFundInEther)
|
|
testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(denominations.One))
|
|
address := common.HexToAddress(account.Address)
|
|
genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds}
|
|
}
|
|
for _, account := range contract.DemoAccounts {
|
|
testBankFunds := big.NewInt(InitFreeFundInEther)
|
|
testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(denominations.One))
|
|
address := common.HexToAddress(account.Address)
|
|
genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds}
|
|
}
|
|
}
|
|
|