Merge pull request #2450 from filecoin-project/feat/seed-msig-work
Feat/seed msig work
This commit is contained in:
commit
a06e685cfc
@ -8,8 +8,10 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
@ -195,8 +197,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
|
|
||||||
// Create accounts
|
// Create accounts
|
||||||
for id, info := range template.Accounts {
|
for id, info := range template.Accounts {
|
||||||
if info.Type != genesis.TAccount {
|
if info.Type != genesis.TAccount && info.Type != genesis.TMultisig {
|
||||||
return nil, xerrors.New("unsupported account type") // TODO: msigs
|
return nil, xerrors.New("unsupported account type")
|
||||||
}
|
}
|
||||||
|
|
||||||
ida, err := address.NewIDAddress(uint64(AccountStart + id))
|
ida, err := address.NewIDAddress(uint64(AccountStart + id))
|
||||||
@ -204,24 +206,57 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ainfo genesis.AccountMeta
|
// var newAddress address.Address
|
||||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
|
||||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
if (info.Type == genesis.TAccount) {
|
||||||
|
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: builtin.AccountActorCodeID,
|
||||||
|
Balance: info.Balance,
|
||||||
|
Head: st,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||||
|
}
|
||||||
|
} else if (info.Type == genesis.TMultisig) {
|
||||||
|
var ainfo genesis.MultisigMeta
|
||||||
|
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||||
|
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to create empty map: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := cst.Put(ctx, &multisig.State{
|
||||||
|
Signers: ainfo.Signers,
|
||||||
|
NumApprovalsThreshold: uint64(ainfo.Threshold),
|
||||||
|
StartEpoch: abi.ChainEpoch(ainfo.VestingStart),
|
||||||
|
UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration),
|
||||||
|
PendingTxns: pending,
|
||||||
|
InitialBalance: info.Balance,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = state.SetActor(ida, &types.Actor{
|
||||||
|
Code: builtin.MultisigActorCodeID,
|
||||||
|
Balance: info.Balance,
|
||||||
|
Head: st,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("setting account from actmap: %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: builtin.AccountActorCodeID,
|
|
||||||
Balance: info.Balance,
|
|
||||||
Head: st,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vregroot, err := address.NewIDAddress(80)
|
vregroot, err := address.NewIDAddress(80)
|
||||||
|
@ -30,6 +30,10 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
|||||||
amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map
|
amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map
|
||||||
|
|
||||||
for i, a := range initialActors {
|
for i, a := range initialActors {
|
||||||
|
if a.Type == genesis.TMultisig {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if a.Type != genesis.TAccount {
|
if a.Type != genesis.TAccount {
|
||||||
return nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here)
|
return nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here)
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,13 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
@ -184,12 +185,19 @@ var msigInspectCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
head, err := api.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var mstate samsig.State
|
var mstate samsig.State
|
||||||
if err := mstate.UnmarshalCBOR(bytes.NewReader(obj)); err != nil {
|
if err := mstate.UnmarshalCBOR(bytes.NewReader(obj)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Balance: %sfil\n", types.FIL(act.Balance))
|
locked := mstate.AmountLocked(head.Height() - mstate.StartEpoch)
|
||||||
|
fmt.Printf("Balance: %s\n", types.FIL(act.Balance))
|
||||||
|
fmt.Printf("Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked)))
|
||||||
fmt.Printf("Threshold: %d / %d\n", mstate.NumApprovalsThreshold, len(mstate.Signers))
|
fmt.Printf("Threshold: %d / %d\n", mstate.NumApprovalsThreshold, len(mstate.Signers))
|
||||||
fmt.Println("Signers:")
|
fmt.Println("Signers:")
|
||||||
for _, s := range mstate.Signers {
|
for _, s := range mstate.Signers {
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/csv"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
@ -10,10 +15,12 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/genesis"
|
"github.com/filecoin-project/lotus/genesis"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +30,7 @@ var genesisCmd = &cli.Command{
|
|||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
genesisNewCmd,
|
genesisNewCmd,
|
||||||
genesisAddMinerCmd,
|
genesisAddMinerCmd,
|
||||||
|
genesisAddMsigsCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,3 +149,153 @@ var genesisAddMinerCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GenAccountEntry struct {
|
||||||
|
Version int
|
||||||
|
ID string
|
||||||
|
Amount types.FIL
|
||||||
|
VestingMonths int
|
||||||
|
CustodianID int
|
||||||
|
M int
|
||||||
|
N int
|
||||||
|
Addresses []address.Address
|
||||||
|
Type string
|
||||||
|
Sig1 string
|
||||||
|
Sig2 string
|
||||||
|
}
|
||||||
|
|
||||||
|
var genesisAddMsigsCmd = &cli.Command{
|
||||||
|
Name: "add-msigs",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() < 2 {
|
||||||
|
return fmt.Errorf("must specify template file and csv file with accounts")
|
||||||
|
}
|
||||||
|
|
||||||
|
genf, err := homedir.Expand(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
csvf, err := homedir.Expand(cctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var template genesis.Template
|
||||||
|
b, err := ioutil.ReadFile(genf)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("read genesis template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &template); err != nil {
|
||||||
|
return xerrors.Errorf("unmarshal genesis template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := parseMultisigCsv(csvf)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing multisig csv file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range entries {
|
||||||
|
if len(e.Addresses) != e.N {
|
||||||
|
return fmt.Errorf("entry %d had mismatch between 'N' and number of addresses", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
msig := &genesis.MultisigMeta{
|
||||||
|
Signers: e.Addresses,
|
||||||
|
Threshold: e.M,
|
||||||
|
VestingDuration: monthsToBlocks(e.VestingMonths),
|
||||||
|
VestingStart: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
act := genesis.Actor{
|
||||||
|
Type: genesis.TMultisig,
|
||||||
|
Balance: abi.TokenAmount(e.Amount),
|
||||||
|
Meta: msig.ActorMeta(),
|
||||||
|
}
|
||||||
|
|
||||||
|
template.Accounts = append(template.Accounts, act)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = json.MarshalIndent(&template, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(genf, b, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func monthsToBlocks(nmonths int) int {
|
||||||
|
days := uint64((365 * nmonths) / 12)
|
||||||
|
return int(days * 24 * 60 * 60 / build.BlockDelaySecs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMultisigCsv(csvf string) ([]GenAccountEntry, error) {
|
||||||
|
fileReader, err := os.Open(csvf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("read multisig csv: %w", err)
|
||||||
|
}
|
||||||
|
r := csv.NewReader(fileReader)
|
||||||
|
records, err := r.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("read multisig csv: %w", err)
|
||||||
|
}
|
||||||
|
var entries []GenAccountEntry
|
||||||
|
for i, e := range records[1:] {
|
||||||
|
var addrs []address.Address
|
||||||
|
addrStrs := strings.Split(strings.TrimSpace(e[7]), ":")
|
||||||
|
for j, a := range addrStrs {
|
||||||
|
addr, err := address.NewFromString(a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse address %d in row %d (%q): %w", j, i, a, err)
|
||||||
|
}
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
balance, err := types.ParseFIL(strings.TrimSpace(e[2]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse account balance: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vesting, err := strconv.Atoi(strings.TrimSpace(e[3]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse vesting duration for record %d: %w", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
custodianID, err := strconv.Atoi(strings.TrimSpace(e[4]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse custodianID in record %d: %w", i, err)
|
||||||
|
}
|
||||||
|
threshold, err := strconv.Atoi(strings.TrimSpace(e[5]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse multisigM in record %d: %w", i, err)
|
||||||
|
}
|
||||||
|
num, err := strconv.Atoi(strings.TrimSpace(e[6]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("Number of addresses be integer: %w", err)
|
||||||
|
}
|
||||||
|
if e[0] != "1" {
|
||||||
|
return nil, xerrors.Errorf("record version must be 1")
|
||||||
|
}
|
||||||
|
entries = append(entries, GenAccountEntry{
|
||||||
|
Version: 1,
|
||||||
|
ID: e[1],
|
||||||
|
Amount: balance,
|
||||||
|
CustodianID: custodianID,
|
||||||
|
VestingMonths: vesting,
|
||||||
|
M: threshold,
|
||||||
|
N: num,
|
||||||
|
Type: e[8],
|
||||||
|
Sig1: e[9],
|
||||||
|
Sig2: e[10],
|
||||||
|
Addresses: addrs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
@ -51,7 +51,18 @@ func (am *AccountMeta) ActorMeta() json.RawMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MultisigMeta struct {
|
type MultisigMeta struct {
|
||||||
// TODO
|
Signers []address.Address
|
||||||
|
Threshold int
|
||||||
|
VestingDuration int
|
||||||
|
VestingStart int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mm *MultisigMeta) ActorMeta() json.RawMessage {
|
||||||
|
out, err := json.Marshal(mm)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
type Actor struct {
|
type Actor struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user