2019-07-25 22:15:03 +00:00
|
|
|
package gen
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
2019-08-29 15:09:34 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/build"
|
2019-07-25 22:15:03 +00:00
|
|
|
actors "github.com/filecoin-project/go-lotus/chain/actors"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/address"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/state"
|
2019-08-15 02:30:21 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/store"
|
2019-07-25 22:15:03 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/types"
|
2019-08-15 02:30:21 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/vm"
|
|
|
|
"golang.org/x/xerrors"
|
2019-07-25 22:15:03 +00:00
|
|
|
|
|
|
|
"github.com/ipfs/go-cid"
|
2019-08-15 02:30:21 +00:00
|
|
|
"github.com/ipfs/go-datastore"
|
2019-07-25 22:15:03 +00:00
|
|
|
hamt "github.com/ipfs/go-hamt-ipld"
|
|
|
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
2019-08-15 02:30:21 +00:00
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
2019-07-25 22:15:03 +00:00
|
|
|
sharray "github.com/whyrusleeping/sharray"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GenesisBootstrap struct {
|
|
|
|
Genesis *types.BlockHeader
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor, error) {
|
|
|
|
var ias actors.InitActorState
|
|
|
|
ias.NextID = 100
|
|
|
|
|
|
|
|
cst := hamt.CSTFromBstore(bs)
|
|
|
|
amap := hamt.NewNode(cst)
|
|
|
|
|
|
|
|
for i, a := range addrs {
|
|
|
|
if err := amap.Set(context.TODO(), string(a.Bytes()), 100+uint64(i)); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ias.NextID += uint64(len(addrs))
|
|
|
|
if err := amap.Flush(context.TODO()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
amapcid, err := cst.Put(context.TODO(), amap)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ias.AddressMap = amapcid
|
|
|
|
|
|
|
|
statecid, err := cst.Put(context.TODO(), &ias)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
act := &types.Actor{
|
|
|
|
Code: actors.InitActorCodeCid,
|
|
|
|
Head: statecid,
|
|
|
|
}
|
|
|
|
|
|
|
|
return act, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types.BigInt) (*state.StateTree, error) {
|
|
|
|
cst := hamt.CSTFromBstore(bs)
|
|
|
|
state, err := state.NewStateTree(cst)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
emptyobject, err := cst.Put(context.TODO(), map[string]string{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var addrs []address.Address
|
|
|
|
for a := range actmap {
|
|
|
|
addrs = append(addrs, a)
|
|
|
|
}
|
|
|
|
|
|
|
|
initact, err := SetupInitActor(bs, addrs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := state.SetActor(actors.InitActorAddress, initact); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
smact, err := SetupStorageMarketActor(bs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := state.SetActor(actors.StorageMarketAddress, smact); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = state.SetActor(actors.NetworkAddress, &types.Actor{
|
|
|
|
Code: actors.AccountActorCodeCid,
|
|
|
|
Balance: types.NewInt(100000000000),
|
|
|
|
Head: emptyobject,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for a, v := range actmap {
|
|
|
|
err = state.SetActor(a, &types.Actor{
|
|
|
|
Code: actors.AccountActorCodeCid,
|
|
|
|
Balance: v,
|
|
|
|
Head: emptyobject,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
|
|
|
sms := &actors.StorageMarketState{
|
|
|
|
Miners: make(map[address.Address]struct{}),
|
|
|
|
TotalStorage: types.NewInt(0),
|
|
|
|
}
|
|
|
|
|
|
|
|
stcid, err := hamt.CSTFromBstore(bs).Put(context.TODO(), sms)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &types.Actor{
|
|
|
|
Code: actors.StorageMarketActorCodeCid,
|
|
|
|
Head: stcid,
|
|
|
|
Nonce: 0,
|
|
|
|
Balance: types.NewInt(0),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-08-15 02:30:21 +00:00
|
|
|
type GenMinerCfg struct {
|
|
|
|
Owner address.Address
|
|
|
|
Worker address.Address
|
|
|
|
|
|
|
|
// not quite generating real sectors yet, but this will be necessary
|
|
|
|
//SectorDir string
|
|
|
|
|
|
|
|
// The address of the created miner, this is set by the genesis setup
|
|
|
|
MinerAddr address.Address
|
|
|
|
|
|
|
|
PeerID peer.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func mustEnc(i interface{}) []byte {
|
|
|
|
enc, err := actors.SerializeParams(i)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return enc
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, error) {
|
|
|
|
vm, err := vm.NewVM(sroot, 0, actors.NetworkAddress, cs)
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
2019-08-15 02:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params := mustEnc(actors.CreateStorageMinerParams{
|
|
|
|
Owner: gmcfg.Owner,
|
|
|
|
Worker: gmcfg.Worker,
|
2019-08-27 19:54:14 +00:00
|
|
|
SectorSize: types.NewInt(build.SectorSize),
|
2019-08-15 02:30:21 +00:00
|
|
|
PeerID: gmcfg.PeerID,
|
|
|
|
})
|
|
|
|
|
|
|
|
rval, err := doExec(ctx, vm, actors.StorageMarketAddress, gmcfg.Owner, actors.SMAMethods.CreateStorageMiner, params)
|
|
|
|
if err != nil {
|
|
|
|
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
maddr, err := address.NewFromBytes(rval)
|
|
|
|
if err != nil {
|
|
|
|
return cid.Undef, err
|
|
|
|
}
|
|
|
|
|
|
|
|
gmcfg.MinerAddr = maddr
|
|
|
|
|
|
|
|
params = mustEnc(actors.UpdateStorageParams{Delta: types.NewInt(5000)})
|
|
|
|
|
|
|
|
_, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SMAMethods.UpdateStorage, params)
|
2019-08-16 20:24:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
|
|
|
|
}
|
2019-08-15 02:30:21 +00:00
|
|
|
|
|
|
|
// UGLY HACKY MODIFICATION OF MINER POWER
|
2019-08-15 18:45:32 +00:00
|
|
|
|
|
|
|
// we have to flush the vm here because it buffers stuff internally for perf reasons
|
|
|
|
if _, err := vm.Flush(ctx); err != nil {
|
|
|
|
return cid.Undef, xerrors.Errorf("vm.Flush failed: %w", err)
|
|
|
|
}
|
|
|
|
|
2019-08-15 02:30:21 +00:00
|
|
|
st := vm.StateTree()
|
|
|
|
mact, err := st.GetActor(maddr)
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return cid.Undef, xerrors.Errorf("get miner actor failed: %w", err)
|
2019-08-15 02:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cst := hamt.CSTFromBstore(cs.Blockstore())
|
|
|
|
var mstate actors.StorageMinerActorState
|
|
|
|
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return cid.Undef, xerrors.Errorf("getting miner actor state failed: %w", err)
|
2019-08-15 02:30:21 +00:00
|
|
|
}
|
|
|
|
mstate.Power = types.NewInt(5000)
|
|
|
|
|
|
|
|
nstate, err := cst.Put(ctx, mstate)
|
|
|
|
if err != nil {
|
|
|
|
return cid.Undef, err
|
|
|
|
}
|
|
|
|
|
|
|
|
mact.Head = nstate
|
|
|
|
if err := st.SetActor(maddr, mact); err != nil {
|
|
|
|
return cid.Undef, err
|
|
|
|
}
|
|
|
|
// End of super haxx
|
|
|
|
|
|
|
|
return vm.Flush(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) {
|
|
|
|
ret, err := vm.ApplyMessage(context.TODO(), &types.Message{
|
|
|
|
To: to,
|
|
|
|
From: from,
|
|
|
|
Method: method,
|
|
|
|
Params: params,
|
|
|
|
GasLimit: types.NewInt(1000000),
|
|
|
|
GasPrice: types.NewInt(0),
|
|
|
|
Value: types.NewInt(0),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ret.ExitCode != 0 {
|
|
|
|
return nil, fmt.Errorf("failed to call method: %s", ret.ActorErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret.Return, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg) (*GenesisBootstrap, error) {
|
|
|
|
ctx := context.Background()
|
2019-07-25 22:15:03 +00:00
|
|
|
|
|
|
|
state, err := MakeInitialStateTree(bs, balances)
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stateroot, err := state.Flush()
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("flush state tree failed: %w", err)
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 02:30:21 +00:00
|
|
|
// temp chainstore
|
|
|
|
cs := store.NewChainStore(bs, datastore.NewMapDatastore())
|
|
|
|
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, gmcfg)
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
|
2019-08-15 02:30:21 +00:00
|
|
|
}
|
|
|
|
|
2019-07-25 22:15:03 +00:00
|
|
|
cst := hamt.CSTFromBstore(bs)
|
2019-08-01 20:40:47 +00:00
|
|
|
|
2019-07-25 22:15:03 +00:00
|
|
|
emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst)
|
|
|
|
if err != nil {
|
2019-08-22 01:29:19 +00:00
|
|
|
return nil, xerrors.Errorf("sharray build failed: %w", err)
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
2019-08-22 01:29:19 +00:00
|
|
|
|
|
|
|
mm := &types.MsgMeta{
|
2019-08-01 20:40:47 +00:00
|
|
|
BlsMessages: emptyroot,
|
|
|
|
SecpkMessages: emptyroot,
|
2019-08-22 01:29:19 +00:00
|
|
|
}
|
|
|
|
mmb, err := mm.ToStorageBlock()
|
2019-08-01 20:40:47 +00:00
|
|
|
if err != nil {
|
2019-08-22 01:29:19 +00:00
|
|
|
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)
|
2019-08-01 20:40:47 +00:00
|
|
|
}
|
|
|
|
|
2019-07-25 22:15:03 +00:00
|
|
|
fmt.Println("Empty Genesis root: ", emptyroot)
|
|
|
|
|
2019-08-15 02:30:21 +00:00
|
|
|
genesisticket := &types.Ticket{
|
|
|
|
VRFProof: []byte("vrf proof"),
|
|
|
|
VDFResult: []byte("i am a vdf result"),
|
|
|
|
VDFProof: []byte("vdf proof"),
|
|
|
|
}
|
|
|
|
|
2019-07-25 22:15:03 +00:00
|
|
|
b := &types.BlockHeader{
|
|
|
|
Miner: actors.InitActorAddress,
|
2019-08-15 02:30:21 +00:00
|
|
|
Tickets: []*types.Ticket{genesisticket},
|
2019-07-25 22:15:03 +00:00
|
|
|
ElectionProof: []byte("the Genesis block"),
|
|
|
|
Parents: []cid.Cid{},
|
|
|
|
Height: 0,
|
|
|
|
ParentWeight: types.NewInt(0),
|
|
|
|
StateRoot: stateroot,
|
2019-08-22 01:29:19 +00:00
|
|
|
Messages: mmb.Cid(),
|
2019-07-25 22:15:03 +00:00
|
|
|
MessageReceipts: emptyroot,
|
2019-08-21 17:15:28 +00:00
|
|
|
BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")},
|
2019-08-27 00:46:39 +00:00
|
|
|
BlockSig: types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")},
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sb, err := b.ToStorageBlock()
|
|
|
|
if err != nil {
|
2019-08-22 01:29:19 +00:00
|
|
|
return nil, xerrors.Errorf("serializing block header failed: %w", err)
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := bs.Put(sb); err != nil {
|
2019-08-22 01:29:19 +00:00
|
|
|
return nil, xerrors.Errorf("putting header to blockstore: %w", err)
|
2019-07-25 22:15:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &GenesisBootstrap{
|
|
|
|
Genesis: b,
|
|
|
|
}, nil
|
|
|
|
}
|
2019-08-16 04:40:59 +00:00
|
|
|
|
|
|
|
type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error)
|
|
|
|
|
|
|
|
func ComputeVRF(ctx context.Context, sign SignFunc, w address.Address, input []byte) ([]byte, error) {
|
|
|
|
|
|
|
|
sig, err := sign(ctx, w, input)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if sig.Type != types.KTBLS {
|
|
|
|
return nil, fmt.Errorf("miner worker address was not a BLS key")
|
|
|
|
}
|
|
|
|
|
|
|
|
return sig.Data, nil
|
|
|
|
}
|