lotus/chain/gen/genesis/genesis.go
2020-02-13 00:52:36 +01:00

271 lines
7.3 KiB
Go

package genesis
import (
"context"
"encoding/json"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/build"
actors "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/genesis"
)
const AccountStart = 100
const MinerStart = 1000
const MaxAccounts = MinerStart - AccountStart
var log = logging.Logger("genesis")
type GenesisBootstrap struct {
Genesis *types.BlockHeader
}
/*
From a list of parameters, create a genesis block / initial state
The process:
- Bootstrap state (MakeInitialStateTree)
- Create empty state
- Make init actor
- Create accounts mappings
- Set NextID to MinerStart
- Setup Reward (1.4B fil)
- Setup Cron
- Create empty power actor
- Create empty market
- Setup burnt fund address
- Initialize account / msig balances
- Instantiate early vm with genesis syscalls
- Create miners
- Each:
- power.CreateMiner, set msg value to PowerBalance
- market.AddFunds with correct value
- market.PublishDeals for related sectors
- Set precommits
- Commit presealed sectors
Data Types:
PreSeal :{
CommR CID
CommD CID
SectorID SectorNumber
Deal market.DealProposal # Start at 0, self-deal!
}
Genesis: {
Accounts: [ # non-miner, non-singleton actors, max len = MaxAccounts
{
Type: "account" / "multisig",
Value: "attofil",
[Meta: {msig settings, account key..}]
},...
],
Miners: [
{
Owner, Worker Addr # ID
MarketBalance, PowerBalance TokenAmount
SectorSize uint64
PreSeals []PreSeal
},...
],
}
*/
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, error) {
// Create empty state tree
cst := cbor.NewCborStore(bs)
state, err := state.NewStateTree(cst)
if err != nil {
return nil, xerrors.Errorf("making new state tree: %w", err)
}
emptyobject, err := cst.Put(context.TODO(), []struct{}{})
if err != nil {
return nil, xerrors.Errorf("failed putting empty object: %w", err)
}
// Create init actor
initact, err := SetupInitActor(bs, template.NetworkName, template.Accounts)
if err != nil {
return nil, xerrors.Errorf("setup init actor: %w", err)
}
if err := state.SetActor(actors.InitAddress, initact); err != nil {
return nil, xerrors.Errorf("set init actor: %w", err)
}
// Setup reward
err = state.SetActor(actors.RewardActor, &types.Actor{
Code: builtin.RewardActorCodeID,
Balance: big.Int{Int: build.InitialReward},
Head: emptyobject, // TODO ?
})
if err != nil {
return nil, xerrors.Errorf("set network account actor: %w", err)
}
// Setup cron
cronact, err := SetupCronActor(bs)
if err != nil {
return nil, xerrors.Errorf("setup cron actor: %w", err)
}
if err := state.SetActor(actors.CronAddress, cronact); err != nil {
return nil, xerrors.Errorf("set cron actor: %w", err)
}
// Create empty power actor
spact, err := SetupStoragePowerActor(bs)
if err != nil {
return nil, xerrors.Errorf("setup storage market actor: %w", err)
}
if err := state.SetActor(actors.StoragePowerAddress, spact); err != nil {
return nil, xerrors.Errorf("set storage market actor: %w", err)
}
// Create empty market actor
marketact, err := SetupStorageMarketActor(bs)
if err != nil {
return nil, xerrors.Errorf("setup storage market actor: %w", err)
}
if err := state.SetActor(actors.StorageMarketAddress, marketact); err != nil {
return nil, xerrors.Errorf("set market actor: %w", err)
}
// Setup burnt-funds
err = state.SetActor(actors.BurntFundsAddress, &types.Actor{
Code: actors.AccountCodeCid,
Balance: types.NewInt(0),
Head: emptyobject,
})
if err != nil {
return nil, xerrors.Errorf("set burnt funds account actor: %w", err)
}
// Create accounts
for id, info := range template.Accounts {
if info.Type != genesis.TAccount {
return nil, xerrors.New("unsupported account type") // TODO: msigs
}
ida, err := address.NewIDAddress(uint64(AccountStart + id))
if err != nil {
return nil, err
}
var ainfo genesis.AccountMeta
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
}
st, err := cst.Put(ctx, account.State{Address: ainfo.Owner})
if err != nil {
return nil, err
}
err = state.SetActor(ida, &types.Actor{
Code: actors.AccountCodeCid,
Balance: info.Balance,
Head: st,
})
if err != nil {
return nil, xerrors.Errorf("setting account from actmap: %w", err)
}
}
return state, nil
}
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys *types.VMSyscalls, template genesis.Template) (*GenesisBootstrap, error) {
st, err := MakeInitialStateTree(ctx, bs, template)
if err != nil {
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
}
stateroot, err := st.Flush(ctx)
if err != nil {
return nil, xerrors.Errorf("flush state tree failed: %w", err)
}
// temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners)
if err != nil {
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
}
cst := cbor.NewCborStore(bs)
emptyroot, err := amt.FromArray(ctx, cst, nil)
if err != nil {
return nil, xerrors.Errorf("amt build failed: %w", err)
}
mm := &types.MsgMeta{
BlsMessages: emptyroot,
SecpkMessages: emptyroot,
}
mmb, err := mm.ToStorageBlock()
if err != nil {
return nil, xerrors.Errorf("serializing msgmeta failed: %w", err)
}
if err := bs.Put(mmb); err != nil {
return nil, xerrors.Errorf("putting msgmeta block to blockstore: %w", err)
}
log.Infof("Empty Genesis root: %s", emptyroot)
genesisticket := &types.Ticket{
VRFProof: []byte("vrf proof0000000vrf proof0000000"),
}
b := &types.BlockHeader{
Miner: actors.InitAddress,
Ticket: genesisticket,
EPostProof: types.EPostProof{
Proof: []byte("not a real proof"),
PostRand: []byte("i guess this is kinda random"),
},
Parents: []cid.Cid{},
Height: 0,
ParentWeight: types.NewInt(0),
ParentStateRoot: stateroot,
Messages: mmb.Cid(),
ParentMessageReceipts: emptyroot,
BLSAggregate: crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("signatureeee")},
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("block signatureeee")},
Timestamp: template.Timestamp,
}
sb, err := b.ToStorageBlock()
if err != nil {
return nil, xerrors.Errorf("serializing block header failed: %w", err)
}
if err := bs.Put(sb); err != nil {
return nil, xerrors.Errorf("putting header to blockstore: %w", err)
}
return &GenesisBootstrap{
Genesis: b,
}, nil
}