Merge pull request #74 from filecoin-project/feat/payment-channels
implement initial payment channel actor
This commit is contained in:
commit
663cdbe167
@ -87,7 +87,7 @@ type FullNode interface {
|
|||||||
WalletNew(context.Context, string) (address.Address, error)
|
WalletNew(context.Context, string) (address.Address, error)
|
||||||
WalletList(context.Context) ([]address.Address, error)
|
WalletList(context.Context) ([]address.Address, error)
|
||||||
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
||||||
WalletSign(context.Context, address.Address, []byte) (*chain.Signature, error)
|
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
|
||||||
WalletDefaultAddress(context.Context) (address.Address, error)
|
WalletDefaultAddress(context.Context) (address.Address, error)
|
||||||
|
|
||||||
// Really not sure where this belongs. It could go on the wallet, or the message pool, or the chain...
|
// Really not sure where this belongs. It could go on the wallet, or the message pool, or the chain...
|
||||||
|
@ -49,7 +49,7 @@ type FullNodeStruct struct {
|
|||||||
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
|
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
|
||||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||||
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
||||||
WalletSign func(context.Context, address.Address, []byte) (*chain.Signature, error) `perm:"sign"`
|
WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"`
|
||||||
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
|
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
|
||||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ func (c *FullNodeStruct) WalletBalance(ctx context.Context, a address.Address) (
|
|||||||
return c.Internal.WalletBalance(ctx, a)
|
return c.Internal.WalletBalance(ctx, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) WalletSign(ctx context.Context, k address.Address, msg []byte) (*chain.Signature, error) {
|
func (c *FullNodeStruct) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) {
|
||||||
return c.Internal.WalletSign(ctx, k, msg)
|
return c.Internal.WalletSign(ctx, k, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
281
chain/actors/actor_paych.go
Normal file
281
chain/actors/actor_paych.go
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
|
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ChannelClosingDelay = 6 * 60 * 2 // six hours
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cbor.RegisterCborType(PaymentChannelActorState{})
|
||||||
|
cbor.RegisterCborType(PCAConstructorParams{})
|
||||||
|
cbor.RegisterCborType(SignedVoucher{})
|
||||||
|
cbor.RegisterCborType(Merge{})
|
||||||
|
cbor.RegisterCborType(LaneState{})
|
||||||
|
cbor.RegisterCborType(UpdateChannelState{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentChannelActor struct{}
|
||||||
|
|
||||||
|
type LaneState struct {
|
||||||
|
Closed bool
|
||||||
|
Redeemed types.BigInt
|
||||||
|
Nonce uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentChannelActorState struct {
|
||||||
|
From address.Address
|
||||||
|
To address.Address
|
||||||
|
|
||||||
|
ChannelTotal types.BigInt
|
||||||
|
ToSend types.BigInt
|
||||||
|
|
||||||
|
ClosingAt uint64
|
||||||
|
MinCloseHeight uint64
|
||||||
|
|
||||||
|
LaneStates map[uint64]*LaneState
|
||||||
|
|
||||||
|
VerifActor address.Address
|
||||||
|
VerifMethod uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pca PaymentChannelActor) Exports() []interface{} {
|
||||||
|
return []interface{}{
|
||||||
|
0: pca.Constructor,
|
||||||
|
1: pca.UpdateChannelState,
|
||||||
|
2: pca.Close,
|
||||||
|
3: pca.Collect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PCAConstructorParams struct {
|
||||||
|
To address.Address
|
||||||
|
VerifActor address.Address
|
||||||
|
VerifMethod uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pca PaymentChannelActor) Constructor(act *types.Actor, vmctx types.VMContext, params *PCAConstructorParams) ([]byte, ActorError) {
|
||||||
|
var self PaymentChannelActorState
|
||||||
|
self.From = vmctx.Origin()
|
||||||
|
self.To = params.To
|
||||||
|
self.VerifActor = params.VerifActor
|
||||||
|
self.VerifMethod = params.VerifMethod
|
||||||
|
|
||||||
|
storage := vmctx.Storage()
|
||||||
|
c, err := storage.Put(self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := storage.Commit(EmptyCBOR, c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignedVoucher struct {
|
||||||
|
TimeLock uint64
|
||||||
|
SecretPreimage []byte
|
||||||
|
Extra []byte
|
||||||
|
Lane uint64
|
||||||
|
Nonce uint64
|
||||||
|
Amount types.BigInt
|
||||||
|
MinCloseHeight uint64
|
||||||
|
|
||||||
|
Merges []Merge
|
||||||
|
|
||||||
|
Signature types.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
type Merge struct {
|
||||||
|
Lane uint64
|
||||||
|
Nonce uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateChannelState struct {
|
||||||
|
Sv SignedVoucher
|
||||||
|
Secret []byte
|
||||||
|
Proof []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func hash(b []byte) []byte {
|
||||||
|
panic("blake 2b hash pls")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pca PaymentChannelActor) UpdateChannelState(act *types.Actor, vmctx types.VMContext, params *UpdateChannelState) ([]byte, ActorError) {
|
||||||
|
var self PaymentChannelActorState
|
||||||
|
oldstate := vmctx.Storage().GetHead()
|
||||||
|
storage := vmctx.Storage()
|
||||||
|
if err := storage.Get(oldstate, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := params.Sv
|
||||||
|
|
||||||
|
if err := vmctx.VerifySignature(sv.Signature, self.From); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.BlockHeight() < sv.TimeLock {
|
||||||
|
return nil, aerrors.New(2, "cannot use this voucher yet!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.SecretPreimage != nil {
|
||||||
|
if !bytes.Equal(hash(params.Secret), sv.SecretPreimage) {
|
||||||
|
return nil, aerrors.New(3, "Incorrect secret!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.Extra != nil {
|
||||||
|
if self.VerifActor == address.Undef {
|
||||||
|
return nil, aerrors.New(4, "no verifActor for extra data")
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded, err := SerializeParams([]interface{}{sv.Extra, params.Proof})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = vmctx.Send(self.VerifActor, self.VerifMethod, types.NewInt(0), encoded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.New(5, "spend voucher verification failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := self.LaneStates[sv.Lane]
|
||||||
|
if ls.Closed {
|
||||||
|
return nil, aerrors.New(6, "cannot redeem a voucher on a closed lane")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ls.Nonce > sv.Nonce {
|
||||||
|
return nil, aerrors.New(7, "voucher has an outdated nonce, cannot redeem")
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeValue := types.NewInt(0)
|
||||||
|
for _, merge := range sv.Merges {
|
||||||
|
if merge.Lane == sv.Lane {
|
||||||
|
return nil, aerrors.New(8, "voucher cannot merge its own lane")
|
||||||
|
}
|
||||||
|
|
||||||
|
ols := self.LaneStates[merge.Lane]
|
||||||
|
|
||||||
|
if ols.Nonce >= merge.Nonce {
|
||||||
|
return nil, aerrors.New(9, "merge in voucher has outdated nonce, cannot redeem")
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeValue = types.BigAdd(mergeValue, ols.Redeemed)
|
||||||
|
ols.Nonce = merge.Nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
ls.Nonce = sv.Nonce
|
||||||
|
balanceDelta := types.BigSub(sv.Amount, types.BigAdd(mergeValue, ls.Redeemed))
|
||||||
|
ls.Redeemed = sv.Amount
|
||||||
|
|
||||||
|
newSendBalance := types.BigAdd(self.ToSend, balanceDelta)
|
||||||
|
if types.BigCmp(newSendBalance, types.NewInt(0)) < 0 {
|
||||||
|
// TODO: is this impossible?
|
||||||
|
return nil, aerrors.New(10, "voucher would leave channel balance negative")
|
||||||
|
}
|
||||||
|
|
||||||
|
if types.BigCmp(newSendBalance, self.ChannelTotal) > 0 {
|
||||||
|
return nil, aerrors.New(11, "not enough funds in channel to cover voucher")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ToSend = newSendBalance
|
||||||
|
|
||||||
|
if sv.MinCloseHeight != 0 {
|
||||||
|
if self.ClosingAt != 0 && self.ClosingAt < sv.MinCloseHeight {
|
||||||
|
self.ClosingAt = sv.MinCloseHeight
|
||||||
|
}
|
||||||
|
if self.MinCloseHeight < sv.MinCloseHeight {
|
||||||
|
self.MinCloseHeight = sv.MinCloseHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ncid, err := storage.Put(self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := storage.Commit(oldstate, ncid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pca PaymentChannelActor) Close(act *types.Actor, vmctx types.VMContext, params struct{}) ([]byte, aerrors.ActorError) {
|
||||||
|
var self PaymentChannelActorState
|
||||||
|
storage := vmctx.Storage()
|
||||||
|
oldstate := storage.GetHead()
|
||||||
|
if err := storage.Get(oldstate, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.Message().From != self.From && vmctx.Message().From != self.To {
|
||||||
|
return nil, aerrors.New(1, "not authorized to close channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ClosingAt != 0 {
|
||||||
|
return nil, aerrors.New(2, "channel already closing")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ClosingAt = vmctx.BlockHeight() + ChannelClosingDelay
|
||||||
|
if self.ClosingAt < self.MinCloseHeight {
|
||||||
|
self.ClosingAt = self.MinCloseHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
ncid, err := storage.Put(self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := storage.Commit(oldstate, ncid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pca PaymentChannelActor) Collect(act *types.Actor, vmctx types.VMContext, params struct{}) ([]byte, aerrors.ActorError) {
|
||||||
|
var self PaymentChannelActorState
|
||||||
|
storage := vmctx.Storage()
|
||||||
|
oldstate := storage.GetHead()
|
||||||
|
if err := storage.Get(oldstate, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ClosingAt == 0 {
|
||||||
|
return nil, aerrors.New(1, "payment channel not closing or closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmctx.BlockHeight() < self.ClosingAt {
|
||||||
|
return nil, aerrors.New(2, "payment channel not closed yet")
|
||||||
|
}
|
||||||
|
_, err := vmctx.Send(self.From, 0, types.BigSub(self.ChannelTotal, self.ToSend), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = vmctx.Send(self.To, 0, self.ToSend, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ChannelTotal = types.NewInt(0)
|
||||||
|
self.ToSend = types.NewInt(0)
|
||||||
|
|
||||||
|
ncid, err := storage.Put(self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := storage.Commit(oldstate, ncid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
@ -161,7 +161,7 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
|||||||
func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) {
|
func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) {
|
||||||
fmt.Println("at end of make Genesis block")
|
fmt.Println("at end of make Genesis block")
|
||||||
|
|
||||||
minerAddr, err := w.GenerateKey(KTSecp256k1)
|
minerAddr, err := w.GenerateKey(types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func MinerCreateBlock(cs *ChainStore, miner address.Address, parents *TipSet, ti
|
|||||||
|
|
||||||
fmt.Printf("adding %d messages to block...", len(msgs))
|
fmt.Printf("adding %d messages to block...", len(msgs))
|
||||||
var msgCids []cid.Cid
|
var msgCids []cid.Cid
|
||||||
var blsSigs []Signature
|
var blsSigs []types.Signature
|
||||||
var receipts []interface{}
|
var receipts []interface{}
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
if msg.Signature.TypeCode() == 2 {
|
if msg.Signature.TypeCode() == 2 {
|
||||||
@ -108,7 +108,7 @@ func MinerCreateBlock(cs *ChainStore, miner address.Address, parents *TipSet, ti
|
|||||||
return fullBlock, nil
|
return fullBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func aggregateSignatures(sigs []Signature) (Signature, error) {
|
func aggregateSignatures(sigs []types.Signature) (types.Signature, error) {
|
||||||
var blsSigs []bls.Signature
|
var blsSigs []bls.Signature
|
||||||
for _, s := range sigs {
|
for _, s := range sigs {
|
||||||
var bsig bls.Signature
|
var bsig bls.Signature
|
||||||
@ -117,8 +117,8 @@ func aggregateSignatures(sigs []Signature) (Signature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
aggSig := bls.Aggregate(blsSigs)
|
aggSig := bls.Aggregate(blsSigs)
|
||||||
return Signature{
|
return types.Signature{
|
||||||
Type: KTBLS,
|
Type: types.KTBLS,
|
||||||
Data: aggSig[:],
|
Data: aggSig[:],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ func init() {
|
|||||||
return SignedMessage{}, fmt.Errorf("signature in signed message was not bytes")
|
return SignedMessage{}, fmt.Errorf("signature in signed message was not bytes")
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := SignatureFromBytes(sigb)
|
sig, err := types.SignatureFromBytes(sigb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SignedMessage{}, err
|
return SignedMessage{}, err
|
||||||
}
|
}
|
||||||
@ -49,18 +48,6 @@ func init() {
|
|||||||
}, nil
|
}, nil
|
||||||
})).
|
})).
|
||||||
Complete())
|
Complete())
|
||||||
cbor.RegisterCborType(atlas.BuildEntry(Signature{}).Transform().
|
|
||||||
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
|
||||||
func(s Signature) ([]byte, error) {
|
|
||||||
buf := make([]byte, 4)
|
|
||||||
n := binary.PutUvarint(buf, uint64(s.TypeCode()))
|
|
||||||
return append(buf[:n], s.Data...), nil
|
|
||||||
})).
|
|
||||||
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
|
|
||||||
func(x []byte) (Signature, error) {
|
|
||||||
return SignatureFromBytes(x)
|
|
||||||
})).
|
|
||||||
Complete())
|
|
||||||
cbor.RegisterCborType(atlas.BuildEntry(BlockHeader{}).UseTag(43).Transform().
|
cbor.RegisterCborType(atlas.BuildEntry(BlockHeader{}).UseTag(43).Transform().
|
||||||
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
||||||
func(blk BlockHeader) ([]interface{}, error) {
|
func(blk BlockHeader) ([]interface{}, error) {
|
||||||
@ -140,7 +127,7 @@ type BlockHeader struct {
|
|||||||
|
|
||||||
Messages cid.Cid
|
Messages cid.Cid
|
||||||
|
|
||||||
BLSAggregate Signature
|
BLSAggregate types.Signature
|
||||||
|
|
||||||
MessageReceipts cid.Cid
|
MessageReceipts cid.Cid
|
||||||
}
|
}
|
||||||
@ -208,7 +195,7 @@ func (m *SignedMessage) Cid() cid.Cid {
|
|||||||
|
|
||||||
type SignedMessage struct {
|
type SignedMessage struct {
|
||||||
Message types.Message
|
Message types.Message
|
||||||
Signature Signature
|
Signature types.Signature
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeSignedMessage(data []byte) (*SignedMessage, error) {
|
func DecodeSignedMessage(data []byte) (*SignedMessage, error) {
|
||||||
|
92
chain/types/signature.go
Normal file
92
chain/types/signature.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/crypto"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
"github.com/minio/blake2b-simd"
|
||||||
|
"github.com/polydawn/refmt/obj/atlas"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KTSecp256k1 = "secp256k1"
|
||||||
|
KTBLS = "bls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cbor.RegisterCborType(atlas.BuildEntry(Signature{}).Transform().
|
||||||
|
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
||||||
|
func(s Signature) ([]byte, error) {
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
n := binary.PutUvarint(buf, uint64(s.TypeCode()))
|
||||||
|
return append(buf[:n], s.Data...), nil
|
||||||
|
})).
|
||||||
|
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
|
||||||
|
func(x []byte) (Signature, error) {
|
||||||
|
return SignatureFromBytes(x)
|
||||||
|
})).
|
||||||
|
Complete())
|
||||||
|
}
|
||||||
|
|
||||||
|
type Signature struct {
|
||||||
|
Type string
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignatureFromBytes(x []byte) (Signature, error) {
|
||||||
|
val, nr := binary.Uvarint(x)
|
||||||
|
if nr != 1 {
|
||||||
|
return Signature{}, fmt.Errorf("signatures with type field longer than one byte are invalid")
|
||||||
|
}
|
||||||
|
var ts string
|
||||||
|
switch val {
|
||||||
|
case 1:
|
||||||
|
ts = KTSecp256k1
|
||||||
|
default:
|
||||||
|
return Signature{}, fmt.Errorf("unsupported signature type: %d", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Signature{
|
||||||
|
Type: ts,
|
||||||
|
Data: x[1:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Signature) Verify(addr address.Address, msg []byte) error {
|
||||||
|
b2sum := blake2b.Sum256(msg)
|
||||||
|
|
||||||
|
switch s.Type {
|
||||||
|
case KTSecp256k1:
|
||||||
|
pubk, err := crypto.EcRecover(b2sum[:], s.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
maybeaddr, err := address.NewSecp256k1Address(pubk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr != maybeaddr {
|
||||||
|
return fmt.Errorf("signature did not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Signature) TypeCode() int {
|
||||||
|
switch s.Type {
|
||||||
|
case KTSecp256k1:
|
||||||
|
return 1
|
||||||
|
case KTBLS:
|
||||||
|
return 2
|
||||||
|
default:
|
||||||
|
panic("unsupported signature type")
|
||||||
|
}
|
||||||
|
}
|
@ -32,4 +32,5 @@ type VMContext interface {
|
|||||||
GasUsed() BigInt
|
GasUsed() BigInt
|
||||||
Storage() Storage
|
Storage() Storage
|
||||||
StateTree() (StateTree, aerrors.ActorError)
|
StateTree() (StateTree, aerrors.ActorError)
|
||||||
|
VerifySignature(sig Signature, from address.Address) aerrors.ActorError
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,10 @@ func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) {
|
|||||||
return vmc.state, nil
|
return vmc.state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vmctx *VMContext) VerifySignature(sig types.Signature, act address.Address) aerrors.ActorError {
|
||||||
|
panic("NYI")
|
||||||
|
}
|
||||||
|
|
||||||
func (vm *VM) makeVMContext(sroot cid.Cid, origin address.Address, msg *types.Message) *VMContext {
|
func (vm *VM) makeVMContext(sroot cid.Cid, origin address.Address, msg *types.Message) *VMContext {
|
||||||
cst := hamt.CSTFromBstore(vm.cs.bs)
|
cst := hamt.CSTFromBstore(vm.cs.bs)
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -17,9 +15,6 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
KNamePrefix = "wallet-"
|
KNamePrefix = "wallet-"
|
||||||
|
|
||||||
KTSecp256k1 = "secp256k1"
|
|
||||||
KTBLS = "bls"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Wallet struct {
|
type Wallet struct {
|
||||||
@ -36,91 +31,31 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Signature struct {
|
func (w *Wallet) Sign(addr address.Address, msg []byte) (*types.Signature, error) {
|
||||||
Type string
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignatureFromBytes(x []byte) (Signature, error) {
|
|
||||||
val, nr := binary.Uvarint(x)
|
|
||||||
if nr != 1 {
|
|
||||||
return Signature{}, fmt.Errorf("signatures with type field longer than one byte are invalid")
|
|
||||||
}
|
|
||||||
var ts string
|
|
||||||
switch val {
|
|
||||||
case 1:
|
|
||||||
ts = KTSecp256k1
|
|
||||||
default:
|
|
||||||
return Signature{}, fmt.Errorf("unsupported signature type: %d", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Signature{
|
|
||||||
Type: ts,
|
|
||||||
Data: x[1:],
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Signature) Verify(addr address.Address, msg []byte) error {
|
|
||||||
b2sum := blake2b.Sum256(msg)
|
|
||||||
|
|
||||||
switch s.Type {
|
|
||||||
case KTSecp256k1:
|
|
||||||
pubk, err := crypto.EcRecover(b2sum[:], s.Data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
maybeaddr, err := address.NewSecp256k1Address(pubk)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if addr != maybeaddr {
|
|
||||||
return fmt.Errorf("signature did not match")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Signature) TypeCode() int {
|
|
||||||
switch s.Type {
|
|
||||||
case KTSecp256k1:
|
|
||||||
return 1
|
|
||||||
case KTBLS:
|
|
||||||
return 2
|
|
||||||
default:
|
|
||||||
panic("unsupported signature type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) Sign(addr address.Address, msg []byte) (*Signature, error) {
|
|
||||||
ki, err := w.findKey(addr)
|
ki, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ki.Type {
|
switch ki.Type {
|
||||||
case KTSecp256k1:
|
case types.KTSecp256k1:
|
||||||
b2sum := blake2b.Sum256(msg)
|
b2sum := blake2b.Sum256(msg)
|
||||||
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
|
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Signature{
|
return &types.Signature{
|
||||||
Type: KTSecp256k1,
|
Type: types.KTSecp256k1,
|
||||||
Data: sig,
|
Data: sig,
|
||||||
}, nil
|
}, nil
|
||||||
case KTBLS:
|
case types.KTBLS:
|
||||||
var pk bls.PrivateKey
|
var pk bls.PrivateKey
|
||||||
copy(pk[:], ki.PrivateKey)
|
copy(pk[:], ki.PrivateKey)
|
||||||
sig := bls.PrivateKeySign(pk, msg)
|
sig := bls.PrivateKeySign(pk, msg)
|
||||||
|
|
||||||
return &Signature{
|
return &types.Signature{
|
||||||
Type: KTBLS,
|
Type: types.KTBLS,
|
||||||
Data: sig[:],
|
Data: sig[:],
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
@ -180,7 +115,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
|||||||
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
|
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
|
||||||
var k *Key
|
var k *Key
|
||||||
switch typ {
|
switch typ {
|
||||||
case KTSecp256k1:
|
case types.KTSecp256k1:
|
||||||
priv, err := crypto.GenerateKey()
|
priv, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
@ -194,7 +129,7 @@ func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return address.Undef, err
|
return address.Undef, err
|
||||||
}
|
}
|
||||||
case KTBLS:
|
case types.KTBLS:
|
||||||
priv := bls.PrivateKeyGenerate()
|
priv := bls.PrivateKeyGenerate()
|
||||||
ki := types.KeyInfo{
|
ki := types.KeyInfo{
|
||||||
Type: typ,
|
Type: typ,
|
||||||
@ -231,7 +166,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch k.Type {
|
switch k.Type {
|
||||||
case KTSecp256k1:
|
case types.KTSecp256k1:
|
||||||
k.PublicKey = crypto.PublicKey(k.PrivateKey)
|
k.PublicKey = crypto.PublicKey(k.PrivateKey)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -240,7 +175,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
|||||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case KTBLS:
|
case types.KTBLS:
|
||||||
var pk bls.PrivateKey
|
var pk bls.PrivateKey
|
||||||
copy(pk[:], k.PrivateKey)
|
copy(pk[:], k.PrivateKey)
|
||||||
pub := bls.PrivateKeyPublicKey(pk)
|
pub := bls.PrivateKeyPublicKey(pk)
|
||||||
|
1
go.mod
1
go.mod
@ -69,6 +69,7 @@ require (
|
|||||||
go4.org v0.0.0-20190313082347-94abd6928b1d // indirect
|
go4.org v0.0.0-20190313082347-94abd6928b1d // indirect
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
|
||||||
|
google.golang.org/appengine v1.4.0 // indirect
|
||||||
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8
|
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8
|
||||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
|
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
|
||||||
)
|
)
|
||||||
|
@ -123,7 +123,7 @@ func (a *FullNodeAPI) WalletBalance(ctx context.Context, addr address.Address) (
|
|||||||
return a.Chain.GetBalance(addr)
|
return a.Chain.GetBalance(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*chain.Signature, error) {
|
func (a *FullNodeAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) {
|
||||||
return a.Wallet.Sign(k, msg)
|
return a.Wallet.Sign(k, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user