Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add signatures to blocks #159

Merged
merged 1 commit into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?

Expand Down
12 changes: 6 additions & 6 deletions api/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions chain/cbor_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion chain/gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
69 changes: 67 additions & 2 deletions chain/gen/mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
}

Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions chain/gen/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
33 changes: 32 additions & 1 deletion chain/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down
4 changes: 4 additions & 0 deletions chain/types/blockheader.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type BlockHeader struct {
BLSAggregate Signature

MessageReceipts cid.Cid

Timestamp uint64

BlockSig Signature
}

func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
Expand Down
1 change: 1 addition & 0 deletions chain/types/blockheader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")},
}
}

Expand Down
29 changes: 27 additions & 2 deletions chain/types/cbor_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand All @@ -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")
}

Expand Down Expand Up @@ -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
}

Expand Down
4 changes: 4 additions & 0 deletions chain/types/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (
)

const (
IKTUnknown = -1

IKTSecp256k1 = iota
IKTBLS
)
Expand Down Expand Up @@ -117,6 +119,8 @@ func (s *Signature) TypeCode() int {
return IKTSecp256k1
case KTBLS:
return IKTBLS
case "":
return IKTUnknown
default:
panic("unsupported signature type")
}
Expand Down
9 changes: 4 additions & 5 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -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)
}
Expand All @@ -187,15 +187,14 @@ 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))
}

return aast.Address, nil
}

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,
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 4 additions & 2 deletions node/impl/full/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
type ChainAPI struct {
fx.In

WalletAPI

Chain *store.ChainStore
PubSub *pubsub.PubSub
}
Expand Down Expand Up @@ -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
}
Expand Down