Merge pull request #159 from filecoin-project/feat/block-sig
add signatures to blocks
This commit is contained in:
commit
ec9ad75dbc
@ -68,7 +68,7 @@ type FullNode interface {
|
||||
MinerRegister(context.Context, address.Address) error
|
||||
MinerUnregister(context.Context, address.Address) error
|
||||
MinerAddresses(context.Context) ([]address.Address, error)
|
||||
MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error)
|
||||
MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*chain.BlockMsg, error)
|
||||
|
||||
// // UX ?
|
||||
|
||||
|
@ -54,10 +54,10 @@ type FullNodeStruct struct {
|
||||
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
|
||||
|
||||
MinerRegister func(context.Context, address.Address) error `perm:"admin"`
|
||||
MinerUnregister func(context.Context, address.Address) error `perm:"admin"`
|
||||
MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) `perm:"write"`
|
||||
MinerRegister func(context.Context, address.Address) error `perm:"admin"`
|
||||
MinerUnregister func(context.Context, address.Address) error `perm:"admin"`
|
||||
MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*chain.BlockMsg, error) `perm:"write"`
|
||||
|
||||
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
@ -174,8 +174,8 @@ func (c *FullNodeStruct) MinerAddresses(ctx context.Context) ([]address.Address,
|
||||
return c.Internal.MinerAddresses(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) {
|
||||
return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs)
|
||||
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) {
|
||||
return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
|
||||
|
@ -522,6 +522,7 @@ func (t *BlockMsg) UnmarshalCBOR(br io.Reader) error {
|
||||
// t.t.Header (types.BlockHeader)
|
||||
|
||||
t.Header = new(types.BlockHeader)
|
||||
|
||||
if err := t.Header.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fblk, err := MinerCreateBlock(context.TODO(), cg.cs, miner, parents, tickets, proof, msgs)
|
||||
fblk, err := MinerCreateBlock(context.TODO(), cg.cs, cg.w, miner, parents, tickets, proof, msgs, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -8,15 +8,17 @@ import (
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
"github.com/pkg/errors"
|
||||
sharray "github.com/whyrusleeping/sharray"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/store"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/chain/vm"
|
||||
"github.com/filecoin-project/go-lotus/chain/wallet"
|
||||
)
|
||||
|
||||
func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*types.FullBlock, error) {
|
||||
func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Wallet, miner address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, timestamp uint64) (*types.FullBlock, error) {
|
||||
st, err := cs.TipSetState(parents.Cids())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load tipset state")
|
||||
@ -29,8 +31,18 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.A
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owner, err := getMinerOwner(ctx, cs, st, miner)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get miner owner: %w", err)
|
||||
}
|
||||
|
||||
worker, err := getMinerWorker(ctx, cs, st, miner)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
|
||||
// apply miner reward
|
||||
if err := vmi.TransferFunds(actors.NetworkAddress, miner, vm.MiningRewardForBlock(parents)); err != nil {
|
||||
if err := vmi.TransferFunds(actors.NetworkAddress, owner, vm.MiningRewardForBlock(parents)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -121,6 +133,25 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.A
|
||||
pweight := cs.Weight(parents)
|
||||
next.ParentWeight = types.NewInt(pweight)
|
||||
|
||||
// TODO: set timestamp
|
||||
|
||||
nosigbytes, err := next.Serialize()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to serialize block header with no signature: %w", err)
|
||||
}
|
||||
|
||||
waddr, err := vm.ResolveToKeyAddr(vmi.StateTree(), cst, worker)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to resolve miner address to key address: %w", err)
|
||||
}
|
||||
|
||||
sig, err := w.Sign(ctx, waddr, nosigbytes)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign new block: %w", err)
|
||||
}
|
||||
|
||||
next.BlockSig = *sig
|
||||
|
||||
fullBlock := &types.FullBlock{
|
||||
Header: next,
|
||||
BlsMessages: blsMessages,
|
||||
@ -130,6 +161,40 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.A
|
||||
return fullBlock, nil
|
||||
}
|
||||
|
||||
func getMinerWorker(ctx context.Context, cs *store.ChainStore, state cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
rec, err := vm.CallRaw(ctx, cs, &types.Message{
|
||||
To: maddr,
|
||||
From: maddr,
|
||||
Method: actors.MAMethods.GetWorkerAddr,
|
||||
}, state, 0)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
if rec.ExitCode != 0 {
|
||||
return address.Undef, xerrors.Errorf("getWorker failed with exit code %d", rec.ExitCode)
|
||||
}
|
||||
|
||||
return address.NewFromBytes(rec.Return)
|
||||
}
|
||||
|
||||
func getMinerOwner(ctx context.Context, cs *store.ChainStore, state cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
rec, err := vm.CallRaw(ctx, cs, &types.Message{
|
||||
To: maddr,
|
||||
From: maddr,
|
||||
Method: actors.MAMethods.GetOwner,
|
||||
}, state, 0)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
if rec.ExitCode != 0 {
|
||||
return address.Undef, xerrors.Errorf("getOwner failed with exit code %d", rec.ExitCode)
|
||||
}
|
||||
|
||||
return address.NewFromBytes(rec.Return)
|
||||
}
|
||||
|
||||
func aggregateSignatures(sigs []types.Signature) (types.Signature, error) {
|
||||
var blsSigs []bls.Signature
|
||||
for _, s := range sigs {
|
||||
|
@ -304,6 +304,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
|
||||
Messages: mmb.Cid(),
|
||||
MessageReceipts: emptyroot,
|
||||
BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")},
|
||||
BlockSig: types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")},
|
||||
}
|
||||
|
||||
sb, err := b.ToStorageBlock()
|
||||
|
@ -395,6 +395,32 @@ func getMinerWorker(ctx context.Context, cs *store.ChainStore, st cid.Cid, maddr
|
||||
return worker, nil
|
||||
}
|
||||
|
||||
func getMinerOwner(ctx context.Context, cs *store.ChainStore, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
recp, err := vm.CallRaw(ctx, cs, &types.Message{
|
||||
To: maddr,
|
||||
From: maddr,
|
||||
Method: actors.MAMethods.GetOwner,
|
||||
}, st, 0)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
|
||||
}
|
||||
|
||||
if recp.ExitCode != 0 {
|
||||
return address.Undef, xerrors.Errorf("getting miner owner addr failed (exit code %d)", recp.ExitCode)
|
||||
}
|
||||
|
||||
owner, err := address.NewFromBytes(recp.Return)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
if owner.Protocol() == address.ID {
|
||||
return address.Undef, xerrors.Errorf("need to resolve owner address to a pubkeyaddr")
|
||||
}
|
||||
|
||||
return owner, nil
|
||||
}
|
||||
|
||||
// Should match up with 'Semantical Validation' in validation.md in the spec
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
||||
h := b.Header
|
||||
@ -426,7 +452,12 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("failed to instantiate VM: %w", err)
|
||||
}
|
||||
|
||||
if err := vmi.TransferFunds(actors.NetworkAddress, b.Header.Miner, vm.MiningRewardForBlock(baseTs)); err != nil {
|
||||
owner, err := getMinerOwner(ctx, syncer.store, stateroot, b.Header.Miner)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner owner for block miner failed: %w", err)
|
||||
}
|
||||
|
||||
if err := vmi.TransferFunds(actors.NetworkAddress, owner, vm.MiningRewardForBlock(baseTs)); err != nil {
|
||||
return xerrors.Errorf("fund transfer failed: %w", err)
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,10 @@ type BlockHeader struct {
|
||||
BLSAggregate Signature
|
||||
|
||||
MessageReceipts cid.Cid
|
||||
|
||||
Timestamp uint64
|
||||
|
||||
BlockSig Signature
|
||||
}
|
||||
|
||||
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
|
@ -39,6 +39,7 @@ func testBlockHeader(t testing.TB) *BlockHeader {
|
||||
Messages: c,
|
||||
Height: 85919298723,
|
||||
StateRoot: c,
|
||||
BlockSig: Signature{Type: KTBLS, Data: []byte("boo! im a signature")},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
var _ = xerrors.Errorf
|
||||
|
||||
func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
|
||||
if _, err := w.Write([]byte{138}); err != nil {
|
||||
if _, err := w.Write([]byte{140}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -80,6 +80,16 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
|
||||
if err := cbg.WriteCid(w, t.MessageReceipts); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.MessageReceipts: %w", err)
|
||||
}
|
||||
|
||||
// t.t.Timestamp (uint64)
|
||||
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Timestamp)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.t.BlockSig (types.Signature)
|
||||
if err := t.BlockSig.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -93,7 +103,7 @@ func (t *BlockHeader) UnmarshalCBOR(br io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 10 {
|
||||
if extra != 12 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
@ -216,6 +226,21 @@ func (t *BlockHeader) UnmarshalCBOR(br io.Reader) error {
|
||||
}
|
||||
t.MessageReceipts = c
|
||||
}
|
||||
// t.t.Timestamp (uint64)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Timestamp = extra
|
||||
// t.t.BlockSig (types.Signature)
|
||||
|
||||
if err := t.BlockSig.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
IKTUnknown = -1
|
||||
|
||||
IKTSecp256k1 = iota
|
||||
IKTBLS
|
||||
)
|
||||
@ -117,6 +119,8 @@ func (s *Signature) TypeCode() int {
|
||||
return IKTSecp256k1
|
||||
case KTBLS:
|
||||
return IKTBLS
|
||||
case "":
|
||||
return IKTUnknown
|
||||
default:
|
||||
panic("unsupported signature type")
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ func (vmctx *VMContext) VerifySignature(sig *types.Signature, act address.Addres
|
||||
}
|
||||
|
||||
if act.Protocol() == address.ID {
|
||||
kaddr, err := vmctx.resolveToKeyAddr(act)
|
||||
kaddr, err := ResolveToKeyAddr(vmctx.state, vmctx.cst, act)
|
||||
if err != nil {
|
||||
return aerrors.Wrap(err, "failed to resolve address to key address")
|
||||
}
|
||||
@ -172,12 +172,12 @@ func (vmctx *VMContext) VerifySignature(sig *types.Signature, act address.Addres
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vmctx *VMContext) resolveToKeyAddr(addr address.Address) (address.Address, aerrors.ActorError) {
|
||||
func ResolveToKeyAddr(state types.StateTree, cst *hamt.CborIpldStore, addr address.Address) (address.Address, aerrors.ActorError) {
|
||||
if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
act, err := vmctx.state.GetActor(addr)
|
||||
act, err := state.GetActor(addr)
|
||||
if err != nil {
|
||||
return address.Undef, aerrors.Newf(1, "failed to find actor: %s", addr)
|
||||
}
|
||||
@ -187,7 +187,7 @@ func (vmctx *VMContext) resolveToKeyAddr(addr address.Address) (address.Address,
|
||||
}
|
||||
|
||||
var aast actors.AccountActorState
|
||||
if err := vmctx.cst.Get(context.TODO(), act.Head, &aast); err != nil {
|
||||
if err := cst.Get(context.TODO(), act.Head, &aast); err != nil {
|
||||
return address.Undef, aerrors.Escalate(err, fmt.Sprintf("failed to get account actor state for %s", addr))
|
||||
}
|
||||
|
||||
@ -195,7 +195,6 @@ func (vmctx *VMContext) resolveToKeyAddr(addr address.Address) (address.Address,
|
||||
}
|
||||
|
||||
func (vm *VM) makeVMContext(ctx context.Context, sroot cid.Cid, msg *types.Message, origin address.Address, usedGas types.BigInt) *VMContext {
|
||||
|
||||
return &VMContext{
|
||||
ctx: ctx,
|
||||
vm: vm,
|
||||
|
1
go.mod
1
go.mod
@ -64,6 +64,7 @@ require (
|
||||
github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a
|
||||
github.com/smartystreets/assertions v1.0.1 // indirect
|
||||
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
|
||||
github.com/stretchr/objx v0.1.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20190822012446-bb2210dd2804
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
|
||||
|
@ -336,7 +336,7 @@ func (m *Miner) createBlock(base *MiningBase, ticket *types.Ticket, proof types.
|
||||
msgs := m.selectMessages(pending)
|
||||
|
||||
// why even return this? that api call could just submit it for us
|
||||
return m.api.MinerCreateBlock(context.TODO(), m.addresses[0], base.ts, append(base.tickets, ticket), proof, msgs)
|
||||
return m.api.MinerCreateBlock(context.TODO(), m.addresses[0], base.ts, append(base.tickets, ticket), proof, msgs, 0)
|
||||
}
|
||||
|
||||
func (m *Miner) selectMessages(msgs []*types.SignedMessage) []*types.SignedMessage {
|
||||
|
@ -23,6 +23,8 @@ import (
|
||||
type ChainAPI struct {
|
||||
fx.In
|
||||
|
||||
WalletAPI
|
||||
|
||||
Chain *store.ChainStore
|
||||
PubSub *pubsub.PubSub
|
||||
}
|
||||
@ -163,8 +165,8 @@ func (a *ChainAPI) ChainReadState(ctx context.Context, act *types.Actor, ts *typ
|
||||
}
|
||||
|
||||
// This is on ChainAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
|
||||
func (a *ChainAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) {
|
||||
fblk, err := gen.MinerCreateBlock(ctx, a.Chain, addr, parents, tickets, proof, msgs)
|
||||
func (a *ChainAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) {
|
||||
fblk, err := gen.MinerCreateBlock(ctx, a.Chain, a.Wallet, addr, parents, tickets, proof, msgs, ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user